Skip to content

Commit bc257a5

Browse files
authored
feat: set client_max_body_size via Lua (#10)
1 parent c3ac756 commit bc257a5

File tree

6 files changed

+473
-3
lines changed

6 files changed

+473
-3
lines changed

README.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# APISIX Nginx Module
2+
3+
## Directive
4+
5+
### apisix_delay_client_max_body_check [on|off]
6+
7+
default: off
8+
9+
Delay client_max_body_size check until the body is read.

lib/resty/apisix/client.lua

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
local ffi = require("ffi")
2+
local base = require("resty.core.base")
3+
local get_request = base.get_request
4+
local C = ffi.C
5+
local NGX_ERROR = ngx.ERROR
6+
7+
8+
base.allows_subsystem("http")
9+
10+
11+
ffi.cdef([[
12+
typedef intptr_t ngx_int_t;
13+
typedef uintptr_t off_t;
14+
ngx_int_t
15+
ngx_http_apisix_client_set_max_body_size(ngx_http_request_t *r, off_t bytes);
16+
]])
17+
local _M = {}
18+
19+
20+
function _M.set_client_max_body_size(bytes)
21+
local r = get_request()
22+
local ret = C.ngx_http_apisix_client_set_max_body_size(r, tonumber(bytes))
23+
if ret == NGX_ERROR then
24+
return nil, "error while setting client max body size"
25+
end
26+
27+
return true
28+
end
29+
30+
31+
return _M
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
diff --git src/http/ngx_http_core_module.c src/http/ngx_http_core_module.c
2+
index 6388140..a500aab 100644
3+
--- src/http/ngx_http_core_module.c
4+
+++ src/http/ngx_http_core_module.c
5+
@@ -985,7 +985,12 @@ ngx_http_core_find_config_phase(ngx_http_request_t *r,
6+
"http cl:%O max:%O",
7+
r->headers_in.content_length_n, clcf->client_max_body_size);
8+
9+
+#if (NGX_HTTP_APISIX)
10+
+ if (!ngx_http_apisix_delay_client_max_body_check(r)
11+
+ && r->headers_in.content_length_n != -1
12+
+#else
13+
if (r->headers_in.content_length_n != -1
14+
+#endif
15+
&& !r->discard_body
16+
&& clcf->client_max_body_size
17+
&& clcf->client_max_body_size < r->headers_in.content_length_n)
18+
diff --git src/http/ngx_http_request_body.c src/http/ngx_http_request_body.c
19+
index 71d7e9a..2844be9 100644
20+
--- src/http/ngx_http_request_body.c
21+
+++ src/http/ngx_http_request_body.c
22+
@@ -8,6 +8,9 @@
23+
#include <ngx_config.h>
24+
#include <ngx_core.h>
25+
#include <ngx_http.h>
26+
+#if (NGX_HTTP_APISIX)
27+
+#include <ngx_http_apisix_module.h>
28+
+#endif
29+
30+
31+
static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
32+
@@ -48,6 +51,25 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
33+
return NGX_OK;
34+
}
35+
36+
+#if (NGX_HTTP_APISIX)
37+
+ if (ngx_http_apisix_delay_client_max_body_check(r)) {
38+
+ off_t max_body_size = ngx_http_apisix_client_max_body_size(r);
39+
+
40+
+ if (r->headers_in.content_length_n != -1
41+
+ && max_body_size
42+
+ && max_body_size < r->headers_in.content_length_n)
43+
+ {
44+
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
45+
+ "client intended to send too large body: %O bytes",
46+
+ r->headers_in.content_length_n);
47+
+
48+
+ r->expect_tested = 1;
49+
+ rc = NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
50+
+ goto done;
51+
+ }
52+
+ }
53+
+#endif
54+
+
55+
if (ngx_http_test_expect(r) != NGX_OK) {
56+
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
57+
goto done;
58+
@@ -1025,6 +1047,10 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
59+
out = NULL;
60+
ll = &out;
61+
62+
+#if (NGX_HTTP_APISIX)
63+
+ off_t max_body_size = ngx_http_apisix_client_max_body_size(r);
64+
+#endif
65+
+
66+
for (cl = in; cl; cl = cl->next) {
67+
68+
b = NULL;
69+
@@ -1048,8 +1074,13 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
70+
71+
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
72+
73+
+#if (NGX_HTTP_APISIX)
74+
+ if (max_body_size
75+
+ && max_body_size
76+
+#else
77+
if (clcf->client_max_body_size
78+
&& clcf->client_max_body_size
79+
+#endif
80+
- r->headers_in.content_length_n < rb->chunked->size)
81+
{
82+
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
83+
diff --git src/http/v2/ngx_http_v2.c src/http/v2/ngx_http_v2.c
84+
index 43a4fde..d22eb4d 100644
85+
--- src/http/v2/ngx_http_v2.c
86+
+++ src/http/v2/ngx_http_v2.c
87+
@@ -4211,10 +4211,18 @@ ngx_http_v2_filter_request_body(ngx_http_request_t *r)
88+
}
89+
90+
} else {
91+
+#if (NGX_HTTP_APISIX)
92+
+ off_t max_body_size = ngx_http_apisix_client_max_body_size(r);
93+
+
94+
+ (void) clcf; /* unused */
95+
+
96+
+ if (max_body_size && rb->received > max_body_size)
97+
+#else
98+
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
99+
100+
if (clcf->client_max_body_size
101+
&& rb->received > clcf->client_max_body_size)
102+
+#endif
103+
{
104+
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
105+
"client intended to send too large chunked body: "

src/ngx_http_apisix_module.c

+101-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,23 @@
44
#include "ngx_http_apisix_module.h"
55

66

7+
static void *ngx_http_apisix_create_loc_conf(ngx_conf_t *cf);
8+
static char *ngx_http_apisix_merge_loc_conf(ngx_conf_t *cf, void *parent,
9+
void *child);
10+
11+
12+
static ngx_command_t ngx_http_apisix_cmds[] = {
13+
{ ngx_string("apisix_delay_client_max_body_check"),
14+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
15+
ngx_conf_set_flag_slot,
16+
NGX_HTTP_LOC_CONF_OFFSET,
17+
offsetof(ngx_http_apisix_loc_conf_t, delay_client_max_body_check),
18+
NULL },
19+
20+
ngx_null_command
21+
};
22+
23+
724
static ngx_http_module_t ngx_http_apisix_module_ctx = {
825
NULL, /* preconfiguration */
926
NULL, /* postconfiguration */
@@ -14,15 +31,15 @@ static ngx_http_module_t ngx_http_apisix_module_ctx = {
1431
NULL, /* create server configuration */
1532
NULL, /* merge server configuration */
1633

17-
NULL, /* create location configuration */
18-
NULL /* merge location configuration */
34+
ngx_http_apisix_create_loc_conf, /* create location configuration */
35+
ngx_http_apisix_merge_loc_conf /* merge location configuration */
1936
};
2037

2138

2239
ngx_module_t ngx_http_apisix_module = {
2340
NGX_MODULE_V1,
2441
&ngx_http_apisix_module_ctx, /* module context */
25-
NULL, /* module directives */
42+
ngx_http_apisix_cmds, /* module directives */
2643
NGX_HTTP_MODULE, /* module type */
2744
NULL, /* init master */
2845
NULL, /* init module */
@@ -35,6 +52,34 @@ ngx_module_t ngx_http_apisix_module = {
3552
};
3653

3754

55+
static void *
56+
ngx_http_apisix_create_loc_conf(ngx_conf_t *cf)
57+
{
58+
ngx_http_apisix_loc_conf_t *conf;
59+
60+
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_apisix_loc_conf_t));
61+
if (conf == NULL) {
62+
return NULL;
63+
}
64+
65+
conf->delay_client_max_body_check = NGX_CONF_UNSET;
66+
67+
return conf;
68+
}
69+
70+
71+
static char *
72+
ngx_http_apisix_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
73+
{
74+
ngx_http_apisix_loc_conf_t *prev = parent;
75+
ngx_http_apisix_loc_conf_t *conf = child;
76+
77+
ngx_conf_merge_value(conf->delay_client_max_body_check,
78+
prev->delay_client_max_body_check, 0);
79+
80+
return NGX_CONF_OK;
81+
}
82+
3883

3984
#if (NGX_HTTP_SSL)
4085
static X509 *
@@ -230,3 +275,56 @@ ngx_http_apisix_set_upstream_ssl(ngx_http_request_t *r, ngx_connection_t *c)
230275
ngx_http_apisix_flush_ssl_error();
231276
}
232277
#endif
278+
279+
280+
ngx_flag_t
281+
ngx_http_apisix_delay_client_max_body_check(ngx_http_request_t *r)
282+
{
283+
ngx_http_apisix_loc_conf_t *alcf;
284+
285+
alcf = ngx_http_get_module_loc_conf(r, ngx_http_apisix_module);
286+
return alcf->delay_client_max_body_check;
287+
}
288+
289+
290+
ngx_int_t
291+
ngx_http_apisix_client_set_max_body_size(ngx_http_request_t *r,
292+
off_t bytes)
293+
{
294+
ngx_http_apisix_ctx_t *ctx;
295+
296+
ctx = ngx_http_apisix_get_module_ctx(r);
297+
298+
if (ctx == NULL) {
299+
return NGX_ERROR;
300+
}
301+
302+
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
303+
"set client max body size %O",
304+
ctx->client_max_body_size);
305+
306+
ctx->client_max_body_size = bytes;
307+
308+
return NGX_OK;
309+
}
310+
311+
312+
off_t
313+
ngx_http_apisix_client_max_body_size(ngx_http_request_t *r)
314+
{
315+
ngx_http_apisix_ctx_t *ctx;
316+
ngx_http_core_loc_conf_t *clcf;
317+
318+
ctx = ngx_http_get_module_ctx(r, ngx_http_apisix_module);
319+
320+
if (ctx != NULL && ctx->client_max_body_size) {
321+
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
322+
"get client max body size %O",
323+
ctx->client_max_body_size);
324+
return ctx->client_max_body_size;
325+
}
326+
327+
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
328+
329+
return clcf->client_max_body_size;
330+
}

src/ngx_http_apisix_module.h

+10
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,23 @@
55
#include <ngx_http.h>
66

77

8+
typedef struct {
9+
ngx_flag_t delay_client_max_body_check;
10+
} ngx_http_apisix_loc_conf_t;
11+
12+
813
typedef struct {
914
STACK_OF(X509) *upstream_cert;
1015
EVP_PKEY *upstream_pkey;
16+
17+
off_t client_max_body_size;
1118
} ngx_http_apisix_ctx_t;
1219

1320

1421
void ngx_http_apisix_set_upstream_ssl(ngx_http_request_t *r, ngx_connection_t *c);
1522

23+
ngx_flag_t ngx_http_apisix_delay_client_max_body_check(ngx_http_request_t *r);
24+
off_t ngx_http_apisix_client_max_body_size(ngx_http_request_t *r);
25+
1626

1727
#endif /* _NGX_HTTP_APISIX_H_INCLUDED_ */

0 commit comments

Comments
 (0)