http check body length

This commit is contained in:
fengzero
2026-09-07 05:56:29 +00:00
parent 8df5acf090
commit 99c86f9b39
8 changed files with 77 additions and 18 deletions
+4
View File
@@ -57,6 +57,10 @@
#define NEU_MSG_MAX_SIZE 2048
#define NEU_PATH_LEN 128
#define NEU_HTTP_BODY_MAX_SIZE (1 * 1024 * 1024)
#define NEU_HTTP_BODY_MAX_SIZE_LARGE (4 * 1024 * 1024)
#define NEU_HTTP_BODY_TOO_BIG (-2)
#define NEU_TAG_META_LENGTH 20
#define NEU_TAG_META_SIZE 32
#define NEU_TAG_FORMAT_LENGTH 16
+4
View File
@@ -35,6 +35,10 @@ extern "C" {
// buffer overflow.
ssize_t neu_url_decode(const char *s, size_t len, char *buf, size_t size);
// Get a NUL terminated copy of the request body, which the caller must free.
// Returns 0 on success, NEU_HTTP_BODY_TOO_BIG if the body exceeds
// NEU_HTTP_BODY_MAX_SIZE_LARGE, and -1 if the body is empty or on allocation
// failure. On failure `*data` is NULL and `*data_size` is zero.
int neu_http_get_body(nng_aio *aio, void **data, size_t *data_size);
// Find query parameter value of the given name.
+20 -15
View File
@@ -25,24 +25,27 @@
#include <nng/nng.h>
#include <nng/supplemental/http/http.h>
#include "define.h"
#include "utils/neu_jwt.h"
#include "json/neu_json_error.h"
#define NEU_PROCESS_HTTP_REQUEST(aio, req_type, decode_fun, func) \
{ \
char * req_data = NULL; \
size_t req_data_size = 0; \
req_type *req = NULL; \
\
if (neu_http_get_body((aio), (void **) &req_data, &req_data_size) == \
0 && \
decode_fun(req_data, &req) == 0) { \
{ func }; \
decode_fun##_free(req); \
} else { \
neu_http_bad_request(aio, "{\"error\": 1002}"); \
} \
free(req_data); \
#define NEU_PROCESS_HTTP_REQUEST(aio, req_type, decode_fun, func) \
{ \
char * req_data = NULL; \
size_t req_data_size = 0; \
req_type *req = NULL; \
int body_rv = \
neu_http_get_body((aio), (void **) &req_data, &req_data_size); \
\
if (0 == body_rv && decode_fun(req_data, &req) == 0) { \
{ func }; \
decode_fun##_free(req); \
} else if (NEU_HTTP_BODY_TOO_BIG == body_rv) { \
neu_http_bad_request(aio, "{\"error\": 1017}"); \
} else { \
neu_http_bad_request(aio, "{\"error\": 1002}"); \
} \
free(req_data); \
}
#define NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(aio, req_type, decode_fun, func) \
@@ -119,6 +122,8 @@ struct neu_http_handler {
char *path;
char *dst_url;
} value;
size_t max_body;
};
int neu_http_add_handler(nng_http_server * server,
+11 -1
View File
@@ -255,25 +255,28 @@ static struct neu_http_handler rest_handlers[] = {
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/tags",
.value.handler = handle_add_tags,
.max_body = NEU_HTTP_BODY_MAX_SIZE_LARGE,
},
{
.method = NEU_HTTP_METHOD_POST,
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/gtags",
.value.handler = handle_add_gtags,
.max_body = NEU_HTTP_BODY_MAX_SIZE_LARGE,
},
{
.method = NEU_HTTP_METHOD_POST,
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/tags/import",
.value.handler = handle_import_tags,
.max_body = NEU_HTTP_BODY_MAX_SIZE_LARGE,
},
{
.method = NEU_HTTP_METHOD_PUT,
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/tags",
.value.handler = handle_update_tags,
.max_body = NEU_HTTP_BODY_MAX_SIZE_LARGE,
},
{
.method = NEU_HTTP_METHOD_GET,
@@ -394,12 +397,14 @@ static struct neu_http_handler rest_handlers[] = {
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/write/tags",
.value.handler = handle_write_tags,
.max_body = NEU_HTTP_BODY_MAX_SIZE_LARGE,
},
{
.method = NEU_HTTP_METHOD_POST,
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/write/gtags",
.value.handler = handle_write_gtags,
.max_body = NEU_HTTP_BODY_MAX_SIZE_LARGE,
},
{
.method = NEU_HTTP_METHOD_POST,
@@ -436,6 +441,7 @@ static struct neu_http_handler rest_handlers[] = {
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/subscribes",
.value.handler = handle_grp_subscribes,
.max_body = NEU_HTTP_BODY_MAX_SIZE_LARGE,
},
{
.method = NEU_HTTP_METHOD_GET,
@@ -502,12 +508,14 @@ static struct neu_http_handler rest_handlers[] = {
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/global/config",
.value.handler = handle_put_global_config,
.max_body = NEU_HTTP_BODY_MAX_SIZE_LARGE,
},
{
.method = NEU_HTTP_METHOD_PUT,
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/global/drivers",
.value.handler = handle_put_drivers,
.max_body = NEU_HTTP_BODY_MAX_SIZE_LARGE,
},
{
.method = NEU_HTTP_METHOD_GET,
@@ -526,6 +534,7 @@ static struct neu_http_handler rest_handlers[] = {
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/global/apps",
.value.handler = handle_put_apps,
.max_body = NEU_HTTP_BODY_MAX_SIZE_LARGE,
},
{
.method = NEU_HTTP_METHOD_GET,
@@ -730,6 +739,7 @@ static struct neu_http_handler rest_handlers[] = {
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/simulator/config",
.value.handler = handle_simulator_set_config,
.max_body = NEU_HTTP_BODY_MAX_SIZE_LARGE,
},
{
.method = NEU_HTTP_METHOD_GET,
+10
View File
@@ -100,8 +100,18 @@ int neu_http_get_body(nng_aio *aio, void **data, size_t *data_size)
nng_http_req_get_data(req, data, data_size);
if (*data_size == 0) {
return -1;
} else if (*data_size > NEU_HTTP_BODY_MAX_SIZE_LARGE) {
nlog_error("<%p> request body too big: %zu", aio, *data_size);
*data = NULL;
*data_size = 0;
return NEU_HTTP_BODY_TOO_BIG;
} else {
char *buf = calloc(*data_size + 1, sizeof(char));
if (NULL == buf) {
*data = NULL;
*data_size = 0;
return -1;
}
memcpy(buf, *data, *data_size);
*data = buf;
return 0;
+7
View File
@@ -24,6 +24,7 @@
#include <nng/nng.h>
#include <nng/supplemental/http/http.h>
#include "define.h"
#include "utils/http_handler.h"
#include "utils/log.h"
@@ -53,6 +54,12 @@ int neu_http_add_handler(nng_http_server * server,
return -1;
}
if (NEU_HTTP_HANDLER_FUNCTION == http_handler->type) {
size_t max_body = http_handler->max_body > 0 ? http_handler->max_body
: NEU_HTTP_BODY_MAX_SIZE;
nng_http_handler_collect_body(handler, true, max_body);
}
switch (http_handler->method) {
case NEU_HTTP_METHOD_GET:
ret = nng_http_handler_set_method(handler, "GET");
+19
View File
@@ -1,5 +1,7 @@
import copy
import requests
import neuron.api as api
import neuron.error as error
import neuron.config as config
@@ -649,6 +651,23 @@ class TestHttp:
assert 1 == len(response.json()["groups"])
@description(given="running neuron", when="post an over sized body", then="should be rejected before parsing")
def test_body_too_big(self):
# far above the 1MB cap of an ordinary endpoint, but below the 4MB
# cap of the bulk endpoints
payload = '{"name": "' + 'a' * (2 * 1024 * 1024) + '"}'
headers = {"Authorization": config.default_jwt,
"Content-Type": "application/json"}
response = requests.post(
url=config.BASE_URL + '/api/v2/node', headers=headers, data=payload)
assert 400 == response.status_code
assert error.NEU_ERR_BODY_TOO_BIG == response.json()['error']
# neuron is still alive and serving after the rejection
response = api.get_version()
assert 200 == response.status_code
@description(given="running neuron", when="test jwt error", then="failed")
def test_jwt_err(self):
response = api.change_password(new_password='123456', jwt='invalid')
+2 -2
View File
@@ -16,8 +16,8 @@ NEU_ERR_DUPLICATE_PASSWORD = 1013
NEU_ERR_COMMAND_EXECUTION_FAILED = 1014
NEU_ERR_IP_ADDRESS_INVALID = 1015
NEU_ERR_IP_ADDRESS_IN_USE = 1016
NEU_ERR_INVALID_USER = 1017
NEU_ERR_INVALID_PASSWORD = 1018
NEU_ERR_BODY_TOO_BIG = 1017
NEU_ERR_INVALID_CID = 1018
NEU_ERR_NODE_EXIST = 2002
NEU_ERR_NODE_NOT_EXIST = 2003