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

shreemaanabhishek 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 945e077e7 feat(limit-count): make rate-limit response headers 
configurable (#11831)
945e077e7 is described below

commit 945e077e7164789af0292eb7df90271c37470392
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Wed Dec 18 16:48:36 2024 +0545

    feat(limit-count): make rate-limit response headers configurable (#11831)
---
 apisix/plugins/limit-count.lua        |  5 +--
 apisix/plugins/limit-count/init.lua   | 54 +++++++++++++++++++++++++-----
 docs/en/latest/plugins/limit-count.md | 59 ++++++++++++++++++++++++++++++++
 t/plugin/limit-count5.t               | 63 +++++++++++++++++++++++++++++++++++
 4 files changed, 171 insertions(+), 10 deletions(-)

diff --git a/apisix/plugins/limit-count.lua b/apisix/plugins/limit-count.lua
index ab7c532a5..1472a6db1 100644
--- a/apisix/plugins/limit-count.lua
+++ b/apisix/plugins/limit-count.lua
@@ -24,11 +24,12 @@ local _M = {
     priority = 1002,
     name = plugin_name,
     schema = limit_count.schema,
+    metadata_schema = limit_count.metadata_schema,
 }
 
 
-function _M.check_schema(conf)
-    return limit_count.check_schema(conf)
+function _M.check_schema(conf, schema_type)
+    return limit_count.check_schema(conf, schema_type)
 end
 
 
diff --git a/apisix/plugins/limit-count/init.lua 
b/apisix/plugins/limit-count/init.lua
index e7d03028e..08a4c9763 100644
--- a/apisix/plugins/limit-count/init.lua
+++ b/apisix/plugins/limit-count/init.lua
@@ -42,6 +42,30 @@ local group_conf_lru = core.lrucache.new({
     type = 'plugin',
 })
 
+local metadata_defaults = {
+    limit_header = "X-RateLimit-Limit",
+    remaining_header = "X-RateLimit-Remaining",
+    reset_header = "X-RateLimit-Reset",
+}
+
+local metadata_schema = {
+    type = "object",
+    properties = {
+        limit_header = {
+            type = "string",
+            default = metadata_defaults.limit_header,
+        },
+        remaining_header = {
+            type = "string",
+            default = metadata_defaults.remaining_header,
+        },
+        reset_header = {
+            type = "string",
+            default = metadata_defaults.reset_header,
+        },
+    },
+}
+
 local schema = {
     type = "object",
     properties = {
@@ -91,7 +115,8 @@ local schema = {
 local schema_copy = core.table.deepcopy(schema)
 
 local _M = {
-    schema = schema
+    schema = schema,
+    metadata_schema = metadata_schema,
 }
 
 
@@ -100,7 +125,12 @@ local function group_conf(conf)
 end
 
 
-function _M.check_schema(conf)
+
+function _M.check_schema(conf, schema_type)
+    if schema_type == core.schema.TYPE_METADATA then
+        return core.schema.check(metadata_schema, conf)
+    end
+
     local ok, err = core.schema.check(schema, conf)
     if not ok then
         return false, err
@@ -250,14 +280,22 @@ function _M.rate_limit(conf, ctx, name, cost)
         delay, remaining, reset = lim:incoming(key, cost)
     end
 
+    local metadata = apisix_plugin.plugin_metadata("limit-count")
+    if metadata then
+        metadata = metadata.value
+    else
+        metadata = metadata_defaults
+    end
+    core.log.info("limit-count plugin-metadata: ", 
core.json.delay_encode(metadata))
+
     if not delay then
         local err = remaining
         if err == "rejected" then
             -- show count limit header when rejected
             if conf.show_limit_quota_header then
-                core.response.set_header("X-RateLimit-Limit", conf.count,
-                    "X-RateLimit-Remaining", 0,
-                    "X-RateLimit-Reset", reset)
+                core.response.set_header(metadata.limit_header, conf.count,
+                    metadata.remaining_header, 0,
+                    metadata.reset_header, reset)
             end
 
             if conf.rejected_msg then
@@ -274,9 +312,9 @@ function _M.rate_limit(conf, ctx, name, cost)
     end
 
     if conf.show_limit_quota_header then
-        core.response.set_header("X-RateLimit-Limit", conf.count,
-            "X-RateLimit-Remaining", remaining,
-            "X-RateLimit-Reset", reset)
+        core.response.set_header(metadata.limit_header, conf.count,
+            metadata.remaining_header, remaining,
+            metadata.reset_header, reset)
     end
 end
 
diff --git a/docs/en/latest/plugins/limit-count.md 
b/docs/en/latest/plugins/limit-count.md
index 4c019332a..c5c225017 100644
--- a/docs/en/latest/plugins/limit-count.md
+++ b/docs/en/latest/plugins/limit-count.md
@@ -344,6 +344,65 @@ Server: APISIX web server
 {"error_msg":"Requests are too frequent, please try again later."}
 ```
 
+### Customize Rate Limiting Headers
+
+The following example demonstrates how you can use plugin metadata to 
customize the rate limiting response header names, which are by default 
`X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset`.
+
+Configure the plugin metadata for this plugin and update the headers:
+
+```shell
+curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/limit-count"; -X PUT 
-d '
+{
+  "log_format": {
+    "limit_header": "X-Custom-RateLimit-Limit",
+    "remaining_header": "X-Custom-RateLimit-Remaining",
+    "reset_header": "X-Custom-RateLimit-Reset"
+  }
+}'
+```
+
+Create a route with `limit-count` plugin that allows for a quota of 1 within a 
30-second window per remote address:
+
+```shell
+curl "http://127.0.0.1:9180/apisix/admin/routes"; -X PUT \
+  -H "X-API-KEY: ${ADMIN_API_KEY}" \
+  -d '{
+    "id": "limit-count-route",
+    "uri": "/get",
+    "plugins": {
+      "limit-count": {
+        "count": 1,
+        "time_window": 30,
+        "rejected_code": 429,
+        "key_type": "var",
+        "key": "remote_addr",
+        "window_type": "sliding"
+      }
+      # highlight-end
+    },
+    "upstream": {
+      "type": "roundrobin",
+      "nodes": {
+        "httpbin.org:80": 1
+      }
+    }
+  }'
+```
+
+Send a request to verify:
+
+```shell
+curl -i "http://127.0.0.1:9080/get";
+```
+
+You should receive an `HTTP/1.1 200 OK` response and see the following headers:
+
+```text
+X-Custom-RateLimit-Limit: 1
+X-Custom-RateLimit-Remaining: 0
+X-Custom-RateLimit-Reset: 28
+```
+
 ## Delete Plugin
 
 To remove the `limit-count` Plugin, you can delete the corresponding JSON 
configuration from the Plugin configuration. APISIX will automatically reload 
and you do not have to restart for this to take effect.
diff --git a/t/plugin/limit-count5.t b/t/plugin/limit-count5.t
index cb4615990..4227b4f10 100644
--- a/t/plugin/limit-count5.t
+++ b/t/plugin/limit-count5.t
@@ -137,3 +137,66 @@ passed
 ["GET /hello", "GET /hello", "GET /hello", "GET /hello"]
 --- error_code eval
 [200, 200, 503, 503]
+
+
+
+=== TEST 4: customize rate limit headers by plugin metadata
+--- 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,
+                 [[{
+                        "methods": ["GET"],
+                        "plugins": {
+                            "limit-count": {
+                                "count": 10,
+                                "time_window": 60,
+                                "rejected_code": 503,
+                                "key_type": "var",
+                                "key": "remote_addr"
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1980": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/hello"
+                }]]
+                )
+            if code >= 300 then
+                ngx.status = code
+                ngx.say("fail")
+                return
+            end
+            local code, meta_body = 
t('/apisix/admin/plugin_metadata/limit-count',
+                 ngx.HTTP_PUT,
+                 [[{
+                        "limit_header":"APISIX-RATELIMIT-QUOTA",
+                        "remaining_header":"APISIX-RATELIMIT-REMAINING",
+                        "reset_header":"APISIX-RATELIMIT-RESET"
+                }]]
+                )
+            if code >= 300 then
+                ngx.status = code
+                ngx.say("fail")
+                return
+            end
+            ngx.say("passed")
+        }
+    }
+--- response_body
+passed
+
+
+
+=== TEST 5: check rate limit headers
+--- request
+GET /hello
+--- response_headers_like
+APISIX-RATELIMIT-QUOTA: 10
+APISIX-RATELIMIT-REMAINING: 9
+APISIX-RATELIMIT-RESET: \d+

Reply via email to