Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(client-control): set client_max_body_size dynamically #4423

Merged
merged 3 commits into from
Jun 16, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apisix/cli/ngx_tpl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,10 @@ http {
log_format main escape={* http.access_log_format_escape *} '{* http.access_log_format *}';
uninitialized_variable_warn off;

{% if use_apisix_openresty then %}
apisix_delay_client_max_body_check on;
{% end %}

access_log {* http.access_log *} main buffer=16384 flush=3;
{% end %}
open_file_cache max=1000 inactive=60;
Expand Down
6 changes: 6 additions & 0 deletions apisix/cli/ops.lua
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,11 @@ Please modify "admin_key" in conf/config.yaml .
with_module_status = false
end

local use_apisix_openresty = true
if or_info and not or_info:find("apisix-nginx-module", 1, true) then
use_apisix_openresty = false
end

local enabled_plugins = {}
for i, name in ipairs(yaml_conf.plugins) do
enabled_plugins[name] = true
Expand Down Expand Up @@ -451,6 +456,7 @@ Please modify "admin_key" in conf/config.yaml .
os_name = util.trim(util.execute_cmd("uname")),
apisix_lua_home = env.apisix_home,
with_module_status = with_module_status,
use_apisix_openresty = use_apisix_openresty,
error_log = {level = "warn"},
enabled_plugins = enabled_plugins,
dubbo_upstream_multiplex_count = dubbo_upstream_multiplex_count,
Expand Down
75 changes: 75 additions & 0 deletions apisix/plugins/client-control.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
--
-- 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 require = require
local core = require("apisix.core")
local _, apisix_ngx_client = pcall(require, "resty.apisix.client")
local tonumber = tonumber


local schema = {
type = "object",
properties = {
max_body_size = {
type = "integer",
minimum = 0,
},
},
}


local plugin_name = "client-control"


local _M = {
version = 0.1,
priority = 22000,
name = plugin_name,
schema = schema,
}


function _M.check_schema(conf)
return core.schema.check(schema, conf)
end


function _M.rewrite(conf, ctx)
if not apisix_ngx_client then
core.log.error("need to build APISIX-OpenResty to support client restriction")
return 503
end

if conf.max_body_size then
local len = tonumber(core.request.header(ctx, "Content-Length"))
if len then
-- if length is given in the header, check it immediately
if conf.max_body_size ~= 0 and len > conf.max_body_size then
return 413
end
end

-- then check it when reading the body
local ok, err = apisix_ngx_client.set_client_max_body_size(conf.max_body_size)
if not ok then
core.log.error("failed to set client max body size: ", err)
return 503
end
end
end


return _M
2 changes: 1 addition & 1 deletion apisix/upstream.lua
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ if ok then
set_upstream_tls_client_param = apisix_ngx_upstream.set_cert_and_key
else
set_upstream_tls_client_param = function ()
return nil, "need to build APISIX-Openresty to support upstream mTLS"
return nil, "need to build APISIX-OpenResty to support upstream mTLS"
end
end

Expand Down
1 change: 1 addition & 0 deletions conf/config-default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ graphql:
#cmd: ["ls", "-l"]

plugins: # plugin list (sorted by priority)
- client-control # priority: 22000
- ext-plugin-pre-req # priority: 12000
- zipkin # priority: 11011
- request-id # priority: 11010
Expand Down
3 changes: 2 additions & 1 deletion docs/en/latest/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@
"plugins/proxy-mirror",
"plugins/api-breaker",
"plugins/traffic-split",
"plugins/request-id"
"plugins/request-id",
"plugins/client-control"
]
},
{
Expand Down
104 changes: 104 additions & 0 deletions docs/en/latest/plugins/client-control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
---
title: client-control
---

<!--
#
# 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.
#
-->

## Summary

- [**Name**](#name)
- [**Attributes**](#attributes)
- [**How To Enable**](#how-to-enable)
- [**Test Plugin**](#test-plugin)
- [**Disable Plugin**](#disable-plugin)

## Name

The `client-control` plugin dynamically controls the behavior of Nginx to
handle the client request.

This plugin requires APISIX to run on [APISIX-OpenResty](../how-to-build.md#6-build-openresty-for-apisix).

## Attributes

| Name | Type | Requirement | Default | Valid | Description |
| --------- | ------------- | ----------- | ---------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| max_body_size | integer | optional | | >= 0 | dynamically set the `client_max_body_size` directive |

## How To Enable

Here's an example, enable this plugin on the specified route:

```shell
curl -i http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/index.html",
"plugins": {
"client-control": {
"max_body_size" : 1
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"39.97.63.215:80": 1
}
}
}'
```

## Test Plugin

Use curl to access:

```shell
curl -i http://127.0.0.1:9080/index.html -d '123'

HTTP/1.1 413 Request Entity Too Large
...
<html>
<head><title>413 Request Entity Too Large</title></head>
<body>
<center><h1>413 Request Entity Too Large</h1></center>
<hr><center>openresty</center>
</body>
</html>
```

## Disable Plugin

When you want to disable this plugin, it is very simple,
you can delete the corresponding json configuration in the plugin configuration,
no need to restart the service, it will take effect immediately:

```shell
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"39.97.63.215:80": 1
}
}
}'
```

This plugin has been disabled now. It works for other plugins.
2 changes: 1 addition & 1 deletion docs/en/latest/plugins/ext-plugin-pre-req.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ title: ext-plugin-pre-req
## Name

The `ext-plugin-pre-req` runs specific external plugins in the plugin runner, before
executing any builtin Lua plugins.
executing most of the builtin Lua plugins.

To know what is the plugin runner, see [external plugin](../external-plugin.md) section.

Expand Down
9 changes: 9 additions & 0 deletions t/APISIX.pm
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,13 @@ my $grpc_location = <<_EOC_;
}
_EOC_

my $a6_ngx_directives = "";
if ($version =~ m/\/apisix-nginx-module/) {
$a6_ngx_directives = <<_EOC_;
apisix_delay_client_max_body_check on;
_EOC_
}

add_block_preprocessor(sub {
my ($block) = @_;
my $wait_etcd_sync = $block->wait_etcd_sync // 0.1;
Expand Down Expand Up @@ -462,6 +469,8 @@ _EOC_
}
}

$a6_ngx_directives

server {
listen 1983 ssl;
ssl_certificate cert/apisix.crt;
Expand Down
2 changes: 1 addition & 1 deletion t/admin/plugins.t
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ __DATA__
--- request
GET /apisix/admin/plugins/list
--- response_body_like eval
qr/\["ext-plugin-pre-req","zipkin","request-id","fault-injection","serverless-pre-function","batch-requests","cors","ip-restriction","referer-restriction","uri-blocker","request-validation","openid-connect","wolf-rbac","hmac-auth","basic-auth","jwt-auth","key-auth","consumer-restriction","authz-keycloak","proxy-mirror","proxy-cache","proxy-rewrite","api-breaker","limit-conn","limit-count","limit-req","server-info","traffic-split","redirect","response-rewrite","grpc-transcode","prometheus","echo","http-logger","sls-logger","tcp-logger","kafka-logger","syslog","udp-logger","example-plugin","serverless-post-function","ext-plugin-post-req"\]/
qr/\["client-control","ext-plugin-pre-req","zipkin","request-id","fault-injection","serverless-pre-function","batch-requests","cors","ip-restriction","referer-restriction","uri-blocker","request-validation","openid-connect","wolf-rbac","hmac-auth","basic-auth","jwt-auth","key-auth","consumer-restriction","authz-keycloak","proxy-mirror","proxy-cache","proxy-rewrite","api-breaker","limit-conn","limit-count","limit-req","server-info","traffic-split","redirect","response-rewrite","grpc-transcode","prometheus","echo","http-logger","sls-logger","tcp-logger","kafka-logger","syslog","udp-logger","example-plugin","serverless-post-function","ext-plugin-post-req"\]/
--- no_error_log
[error]

Expand Down
2 changes: 1 addition & 1 deletion t/core/config.t
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ __DATA__
GET /t
--- response_body
etcd host: http://127.0.0.1:2379
first plugin: "ext-plugin-pre-req"
first plugin: "client-control"



Expand Down
1 change: 1 addition & 0 deletions t/debug/debug-mode.t
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ GET /t
--- response_body
done
--- error_log
loaded plugin and sort by priority: 22000 name: client-control
loaded plugin and sort by priority: 12000 name: ext-plugin-pre-req
loaded plugin and sort by priority: 11011 name: zipkin
loaded plugin and sort by priority: 11010 name: request-id
Expand Down
1 change: 1 addition & 0 deletions t/lib/server.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ end


function _M.hello()
ngx.req.read_body()
local s = "hello world"
ngx.header['Content-Length'] = #s + 1
ngx.say(s)
Expand Down
Loading