Skip to content

Commit

Permalink
Merge branch 'master' of github.com:apache/apisix into revolyssup/cor…
Browse files Browse the repository at this point in the history
…rupt-data-in-route
  • Loading branch information
Revolyssup committed Dec 22, 2024
2 parents e24b9e6 + 945e077 commit 1420a86
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 11 deletions.
8 changes: 7 additions & 1 deletion apisix/core/config_etcd.lua
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,11 @@ local function do_run_watch(premature)
end

local rev = tonumber(res.result.header.revision)
if rev == nil then
log.warn("receive a invalid revision header, header: ", inspect(res.result.header))
cancel_watch(http_cli)
break
end
if rev > watch_ctx.rev then
watch_ctx.rev = rev + 1
end
Expand Down Expand Up @@ -284,7 +289,8 @@ local function run_watch(premature)

local ok, err = ngx_thread_wait(run_watch_th, check_worker_th)
if not ok then
log.error("check_worker thread terminates failed, retart checker, error: " .. err)
log.error("run_watch or check_worker thread terminates failed",
" restart those threads, error: ", inspect(err))
end

ngx_thread_kill(run_watch_th)
Expand Down
5 changes: 3 additions & 2 deletions apisix/plugins/limit-count.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
54 changes: 46 additions & 8 deletions apisix/plugins/limit-count/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -91,7 +115,8 @@ local schema = {
local schema_copy = core.table.deepcopy(schema)

local _M = {
schema = schema
schema = schema,
metadata_schema = metadata_schema,
}


Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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

Expand Down
59 changes: 59 additions & 0 deletions docs/en/latest/plugins/limit-count.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
63 changes: 63 additions & 0 deletions t/plugin/limit-count5.t
Original file line number Diff line number Diff line change
Expand Up @@ -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+

0 comments on commit 1420a86

Please sign in to comment.