Configuration: basic validation of schema.

This commit is contained in:
Valentin Bartenev
2017-07-05 18:44:43 +03:00
parent 4fe5d22dcc
commit 842aa9ab46
5 changed files with 288 additions and 53 deletions

View File

@@ -139,6 +139,7 @@ NXT_LIB_SRCS=" \
src/nxt_app_log.c \ src/nxt_app_log.c \
src/nxt_runtime.c \ src/nxt_runtime.c \
src/nxt_conf.c \ src/nxt_conf.c \
src/nxt_conf_validation.c \
src/nxt_stream_module.c \ src/nxt_stream_module.c \
src/nxt_master_process.c \ src/nxt_master_process.c \
src/nxt_worker_process.c \ src/nxt_worker_process.c \

View File

@@ -17,15 +17,15 @@
typedef enum { typedef enum {
NXT_CONF_NULL = 0, NXT_CONF_VALUE_NULL = 0,
NXT_CONF_BOOLEAN, NXT_CONF_VALUE_BOOLEAN,
NXT_CONF_INTEGER, NXT_CONF_VALUE_INTEGER,
NXT_CONF_NUMBER, NXT_CONF_VALUE_NUMBER,
NXT_CONF_SHORT_STRING, NXT_CONF_VALUE_SHORT_STRING,
NXT_CONF_STRING, NXT_CONF_VALUE_STRING,
NXT_CONF_ARRAY, NXT_CONF_VALUE_ARRAY,
NXT_CONF_OBJECT, NXT_CONF_VALUE_OBJECT,
} nxt_conf_type_t; } nxt_conf_value_type_t;
typedef enum { typedef enum {
@@ -51,7 +51,7 @@ struct nxt_conf_value_s {
nxt_conf_object_t *object; nxt_conf_object_t *object;
} u; } u;
nxt_conf_type_t type:8; /* 3 bits. */ nxt_conf_value_type_t type:8; /* 3 bits. */
}; };
@@ -140,7 +140,7 @@ nxt_conf_json_indentation(u_char *p, uint32_t level)
nxt_inline void nxt_inline void
nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str) nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str)
{ {
if (value->type == NXT_CONF_SHORT_STRING) { if (value->type == NXT_CONF_VALUE_SHORT_STRING) {
str->length = value->u.str[0]; str->length = value->u.str[0];
str->start = &value->u.str[1]; str->start = &value->u.str[1];
@@ -150,6 +150,40 @@ nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str)
} }
nxt_uint_t
nxt_conf_type(nxt_conf_value_t *value)
{
switch (value->type) {
case NXT_CONF_VALUE_NULL:
return NXT_CONF_NULL;
case NXT_CONF_VALUE_BOOLEAN:
return NXT_CONF_BOOLEAN;
case NXT_CONF_VALUE_INTEGER:
return NXT_CONF_INTEGER;
case NXT_CONF_VALUE_NUMBER:
return NXT_CONF_NUMBER;
case NXT_CONF_VALUE_SHORT_STRING:
case NXT_CONF_VALUE_STRING:
return NXT_CONF_STRING;
case NXT_CONF_VALUE_ARRAY:
return NXT_CONF_ARRAY;
case NXT_CONF_VALUE_OBJECT:
return NXT_CONF_OBJECT;
}
nxt_unreachable();
return 0;
}
typedef struct { typedef struct {
u_char *start; u_char *start;
u_char *end; u_char *end;
@@ -225,7 +259,7 @@ nxt_conf_get_object_member(nxt_conf_value_t *value, nxt_str_t *name,
nxt_conf_object_t *object; nxt_conf_object_t *object;
nxt_conf_object_member_t *member; nxt_conf_object_member_t *member;
if (value->type != NXT_CONF_OBJECT) { if (value->type != NXT_CONF_VALUE_OBJECT) {
return NULL; return NULL;
} }
@@ -273,7 +307,7 @@ nxt_conf_map_object(nxt_conf_value_t *value, nxt_conf_map_t *map, void *data)
v = nxt_conf_get_object_member(value, &map[i].name, NULL); v = nxt_conf_get_object_member(value, &map[i].name, NULL);
if (v == NULL || v->type == NXT_CONF_NULL) { if (v == NULL || v->type == NXT_CONF_VALUE_NULL) {
continue; continue;
} }
@@ -283,7 +317,7 @@ nxt_conf_map_object(nxt_conf_value_t *value, nxt_conf_map_t *map, void *data)
case NXT_CONF_MAP_INT8: case NXT_CONF_MAP_INT8:
if (v->type != NXT_CONF_BOOLEAN) { if (v->type != NXT_CONF_VALUE_BOOLEAN) {
return NXT_ERROR; return NXT_ERROR;
} }
@@ -298,7 +332,7 @@ nxt_conf_map_object(nxt_conf_value_t *value, nxt_conf_map_t *map, void *data)
case NXT_CONF_MAP_OFF: case NXT_CONF_MAP_OFF:
case NXT_CONF_MAP_MSEC: case NXT_CONF_MAP_MSEC:
if (v->type != NXT_CONF_INTEGER) { if (v->type != NXT_CONF_VALUE_INTEGER) {
return NXT_ERROR; return NXT_ERROR;
} }
@@ -336,10 +370,10 @@ nxt_conf_map_object(nxt_conf_value_t *value, nxt_conf_map_t *map, void *data)
case NXT_CONF_MAP_DOUBLE: case NXT_CONF_MAP_DOUBLE:
if (v->type == NXT_CONF_NUMBER) { if (v->type == NXT_CONF_VALUE_NUMBER) {
ptr->dbl = v->u.number; ptr->dbl = v->u.number;
} else if (v->type == NXT_CONF_INTEGER) { } else if (v->type == NXT_CONF_VALUE_INTEGER) {
ptr->dbl = v->u.integer; ptr->dbl = v->u.integer;
} else { } else {
@@ -350,8 +384,8 @@ nxt_conf_map_object(nxt_conf_value_t *value, nxt_conf_map_t *map, void *data)
case NXT_CONF_MAP_STR: case NXT_CONF_MAP_STR:
if (v->type != NXT_CONF_SHORT_STRING if (v->type != NXT_CONF_VALUE_SHORT_STRING
&& v->type != NXT_CONF_STRING) && v->type != NXT_CONF_VALUE_STRING)
{ {
return NXT_ERROR; return NXT_ERROR;
} }
@@ -381,7 +415,7 @@ nxt_conf_next_object_member(nxt_conf_value_t *value, nxt_str_t *name,
nxt_conf_object_t *object; nxt_conf_object_t *object;
nxt_conf_object_member_t *member; nxt_conf_object_member_t *member;
if (value->type != NXT_CONF_OBJECT) { if (value->type != NXT_CONF_VALUE_OBJECT) {
return NULL; return NULL;
} }
@@ -466,13 +500,13 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root,
} }
*member->name.u.string = token; *member->name.u.string = token;
member->name.type = NXT_CONF_STRING; member->name.type = NXT_CONF_VALUE_STRING;
} else { } else {
member->name.u.str[0] = token.length; member->name.u.str[0] = token.length;
nxt_memcpy(&member->name.u.str[1], token.start, token.length); nxt_memcpy(&member->name.u.str[1], token.start, token.length);
member->name.type = NXT_CONF_SHORT_STRING; member->name.type = NXT_CONF_VALUE_SHORT_STRING;
} }
member->value = *value; member->value = *value;
@@ -518,7 +552,7 @@ nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
nxt_int_t rc; nxt_int_t rc;
nxt_uint_t n; nxt_uint_t n;
if (op != NULL && src->type != NXT_CONF_OBJECT) { if (op != NULL && src->type != NXT_CONF_VALUE_OBJECT) {
return NXT_ERROR; return NXT_ERROR;
} }
@@ -526,7 +560,7 @@ nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
switch (src->type) { switch (src->type) {
case NXT_CONF_STRING: case NXT_CONF_VALUE_STRING:
dst->u.string = nxt_str_dup(mp, NULL, src->u.string); dst->u.string = nxt_str_dup(mp, NULL, src->u.string);
@@ -536,7 +570,7 @@ nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
break; break;
case NXT_CONF_ARRAY: case NXT_CONF_VALUE_ARRAY:
size = sizeof(nxt_conf_array_t) size = sizeof(nxt_conf_array_t)
+ src->u.array->count * sizeof(nxt_conf_value_t); + src->u.array->count * sizeof(nxt_conf_value_t);
@@ -559,7 +593,7 @@ nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
break; break;
case NXT_CONF_OBJECT: case NXT_CONF_VALUE_OBJECT:
return nxt_conf_copy_object(mp, op, dst, src); return nxt_conf_copy_object(mp, op, dst, src);
default: default:
@@ -780,7 +814,7 @@ nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
&& nxt_memcmp(start, "true", 4) == 0)) && nxt_memcmp(start, "true", 4) == 0))
{ {
value->u.boolean = 1; value->u.boolean = 1;
value->type = NXT_CONF_BOOLEAN; value->type = NXT_CONF_VALUE_BOOLEAN;
return start + 4; return start + 4;
} }
@@ -792,7 +826,7 @@ nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
&& nxt_memcmp(start, "false", 5) == 0)) && nxt_memcmp(start, "false", 5) == 0))
{ {
value->u.boolean = 0; value->u.boolean = 0;
value->type = NXT_CONF_BOOLEAN; value->type = NXT_CONF_VALUE_BOOLEAN;
return start + 5; return start + 5;
} }
@@ -803,7 +837,7 @@ nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
if (nxt_fast_path(end - start >= 4 if (nxt_fast_path(end - start >= 4
&& nxt_memcmp(start, "null", 4) == 0)) && nxt_memcmp(start, "null", 4) == 0))
{ {
value->type = NXT_CONF_NULL; value->type = NXT_CONF_VALUE_NULL;
return start + 4; return start + 4;
} }
@@ -929,7 +963,7 @@ nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
} }
value->u.object = object; value->u.object = object;
value->type = NXT_CONF_OBJECT; value->type = NXT_CONF_VALUE_OBJECT;
object->count = count; object->count = count;
member = object->members; member = object->members;
@@ -1082,7 +1116,7 @@ nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
} }
value->u.array = array; value->u.array = array;
value->type = NXT_CONF_ARRAY; value->type = NXT_CONF_VALUE_ARRAY;
array->count = count; array->count = count;
element = array->elements; element = array->elements;
@@ -1204,7 +1238,7 @@ nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
size = last - start - surplus; size = last - start - surplus;
if (size > NXT_CONF_MAX_SHORT_STRING) { if (size > NXT_CONF_MAX_SHORT_STRING) {
value->type = NXT_CONF_STRING; value->type = NXT_CONF_VALUE_STRING;
value->u.string = nxt_str_alloc(mp, size); value->u.string = nxt_str_alloc(mp, size);
if (nxt_slow_path(value->u.string == NULL)) { if (nxt_slow_path(value->u.string == NULL)) {
@@ -1214,7 +1248,7 @@ nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
s = value->u.string->start; s = value->u.string->start;
} else { } else {
value->type = NXT_CONF_SHORT_STRING; value->type = NXT_CONF_VALUE_SHORT_STRING;
value->u.str[0] = size; value->u.str[0] = size;
s = &value->u.str[1]; s = &value->u.str[1];
@@ -1368,7 +1402,7 @@ nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
} }
if (ch != '.') { if (ch != '.') {
value->type = NXT_CONF_INTEGER; value->type = NXT_CONF_VALUE_INTEGER;
value->u.integer = sign * integer; value->u.integer = sign * integer;
return p; return p;
} }
@@ -1403,7 +1437,7 @@ nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
return NULL; return NULL;
} }
value->type = NXT_CONF_NUMBER; value->type = NXT_CONF_VALUE_NUMBER;
value->u.number = integer + (double) frac / power; value->u.number = integer + (double) frac / power;
value->u.number = copysign(value->u.number, sign); value->u.number = copysign(value->u.number, sign);
@@ -1463,27 +1497,27 @@ nxt_conf_json_length(nxt_conf_value_t *value, nxt_conf_json_pretty_t *pretty)
{ {
switch (value->type) { switch (value->type) {
case NXT_CONF_NULL: case NXT_CONF_VALUE_NULL:
return sizeof("null") - 1; return sizeof("null") - 1;
case NXT_CONF_BOOLEAN: case NXT_CONF_VALUE_BOOLEAN:
return value->u.boolean ? sizeof("true") - 1 : sizeof("false") - 1; return value->u.boolean ? sizeof("true") - 1 : sizeof("false") - 1;
case NXT_CONF_INTEGER: case NXT_CONF_VALUE_INTEGER:
return nxt_conf_json_integer_length(value); return nxt_conf_json_integer_length(value);
case NXT_CONF_NUMBER: case NXT_CONF_VALUE_NUMBER:
/* TODO */ /* TODO */
return 0; return 0;
case NXT_CONF_SHORT_STRING: case NXT_CONF_VALUE_SHORT_STRING:
case NXT_CONF_STRING: case NXT_CONF_VALUE_STRING:
return nxt_conf_json_string_length(value); return nxt_conf_json_string_length(value);
case NXT_CONF_ARRAY: case NXT_CONF_VALUE_ARRAY:
return nxt_conf_json_array_length(value, pretty); return nxt_conf_json_array_length(value, pretty);
case NXT_CONF_OBJECT: case NXT_CONF_VALUE_OBJECT:
return nxt_conf_json_object_length(value, pretty); return nxt_conf_json_object_length(value, pretty);
} }
@@ -1499,28 +1533,28 @@ nxt_conf_json_print(u_char *p, nxt_conf_value_t *value,
{ {
switch (value->type) { switch (value->type) {
case NXT_CONF_NULL: case NXT_CONF_VALUE_NULL:
return nxt_cpymem(p, "null", 4); return nxt_cpymem(p, "null", 4);
case NXT_CONF_BOOLEAN: case NXT_CONF_VALUE_BOOLEAN:
return value->u.boolean ? nxt_cpymem(p, "true", 4) return value->u.boolean ? nxt_cpymem(p, "true", 4)
: nxt_cpymem(p, "false", 5); : nxt_cpymem(p, "false", 5);
case NXT_CONF_INTEGER: case NXT_CONF_VALUE_INTEGER:
return nxt_conf_json_print_integer(p, value); return nxt_conf_json_print_integer(p, value);
case NXT_CONF_NUMBER: case NXT_CONF_VALUE_NUMBER:
/* TODO */ /* TODO */
return p; return p;
case NXT_CONF_SHORT_STRING: case NXT_CONF_VALUE_SHORT_STRING:
case NXT_CONF_STRING: case NXT_CONF_VALUE_STRING:
return nxt_conf_json_print_string(p, value); return nxt_conf_json_print_string(p, value);
case NXT_CONF_ARRAY: case NXT_CONF_VALUE_ARRAY:
return nxt_conf_json_print_array(p, value, pretty); return nxt_conf_json_print_array(p, value, pretty);
case NXT_CONF_OBJECT: case NXT_CONF_VALUE_OBJECT:
return nxt_conf_json_print_object(p, value, pretty); return nxt_conf_json_print_object(p, value, pretty);
} }

View File

@@ -9,6 +9,15 @@
#define _NXT_CONF_INCLUDED_ #define _NXT_CONF_INCLUDED_
#define NXT_CONF_NULL 0x01
#define NXT_CONF_BOOLEAN 0x02
#define NXT_CONF_INTEGER 0x04
#define NXT_CONF_NUMBER 0x08
#define NXT_CONF_STRING 0x10
#define NXT_CONF_ARRAY 0x20
#define NXT_CONF_OBJECT 0x40
typedef struct nxt_conf_value_s nxt_conf_value_t; typedef struct nxt_conf_value_s nxt_conf_value_t;
typedef struct nxt_conf_op_s nxt_conf_op_t; typedef struct nxt_conf_op_s nxt_conf_op_t;
@@ -40,6 +49,8 @@ typedef struct {
} nxt_conf_json_pretty_t; } nxt_conf_json_pretty_t;
nxt_uint_t nxt_conf_type(nxt_conf_value_t *value);
nxt_conf_value_t *nxt_conf_get_path(nxt_conf_value_t *value, nxt_str_t *path); nxt_conf_value_t *nxt_conf_get_path(nxt_conf_value_t *value, nxt_str_t *path);
nxt_conf_value_t *nxt_conf_get_object_member(nxt_conf_value_t *value, nxt_conf_value_t *nxt_conf_get_object_member(nxt_conf_value_t *value,
nxt_str_t *name, uint32_t *index); nxt_str_t *name, uint32_t *index);
@@ -64,5 +75,7 @@ size_t nxt_conf_json_length(nxt_conf_value_t *value,
u_char *nxt_conf_json_print(u_char *p, nxt_conf_value_t *value, u_char *nxt_conf_json_print(u_char *p, nxt_conf_value_t *value,
nxt_conf_json_pretty_t *pretty); nxt_conf_json_pretty_t *pretty);
nxt_int_t nxt_conf_validate(nxt_conf_value_t *value);
#endif /* _NXT_CONF_INCLUDED_ */ #endif /* _NXT_CONF_INCLUDED_ */

173
src/nxt_conf_validation.c Normal file
View File

@@ -0,0 +1,173 @@
/*
* Copyright (C) Valentin V. Bartenev
* Copyright (C) NGINX, Inc.
*/
#include <nxt_main.h>
#include <nxt_conf.h>
typedef struct {
nxt_str_t name;
nxt_uint_t type;
nxt_int_t (*validator)(nxt_conf_value_t *value, void *data);
void *data;
} nxt_conf_vldt_object_t;
typedef nxt_int_t (*nxt_conf_vldt_member_t)(nxt_str_t *name,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_listener(nxt_str_t *name,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_app(nxt_str_t *name, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_app_type(nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_object(nxt_conf_value_t *value, void *data);
static nxt_int_t nxt_conf_vldt_object_iterator(nxt_conf_value_t *value,
void *data);
static const nxt_conf_vldt_object_t nxt_conf_root_members[] = {
{ nxt_string("listeners"),
NXT_CONF_OBJECT,
&nxt_conf_vldt_object_iterator,
&nxt_conf_vldt_listener },
{ nxt_string("applications"),
NXT_CONF_OBJECT,
&nxt_conf_vldt_object_iterator,
&nxt_conf_vldt_app },
{ nxt_null_string, 0, NULL, NULL }
};
static const nxt_conf_vldt_object_t nxt_conf_listener_members[] = {
{ nxt_string("application"),
NXT_CONF_STRING,
NULL,
NULL },
{ nxt_null_string, 0, NULL, NULL }
};
static const nxt_conf_vldt_object_t nxt_conf_application_members[] = {
{ nxt_string("type"),
NXT_CONF_STRING,
&nxt_conf_vldt_app_type,
NULL },
{ nxt_string("path"),
NXT_CONF_STRING,
NULL,
NULL },
{ nxt_null_string, 0, NULL, NULL }
};
nxt_int_t
nxt_conf_validate(nxt_conf_value_t *value)
{
if (nxt_conf_type(value) != NXT_CONF_OBJECT) {
return NXT_ERROR;
}
return nxt_conf_vldt_object(value, (void *) nxt_conf_root_members);
}
static nxt_int_t
nxt_conf_vldt_listener(nxt_str_t *name, nxt_conf_value_t *value)
{
return nxt_conf_vldt_object(value, (void *) nxt_conf_listener_members);
}
static nxt_int_t
nxt_conf_vldt_app(nxt_str_t *name, nxt_conf_value_t *value)
{
return nxt_conf_vldt_object(value, (void *) nxt_conf_application_members);
}
static nxt_int_t
nxt_conf_vldt_app_type(nxt_conf_value_t *value, void *data)
{
// TODO
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_object(nxt_conf_value_t *value, void *data)
{
uint32_t index;
nxt_str_t name;
nxt_conf_value_t *member;
nxt_conf_vldt_object_t *vldt;
index = 0;
for ( ;; ) {
member = nxt_conf_next_object_member(value, &name, &index);
if (member == NULL) {
return NXT_OK;
}
vldt = data;
for ( ;; ) {
if (vldt->name.length == 0) {
return NXT_ERROR;
}
if (!nxt_strstr_eq(&vldt->name, &name)) {
vldt++;
continue;
}
if (nxt_conf_type(member) != vldt->type) {
return NXT_ERROR;
}
if (vldt->validator != NULL
&& vldt->validator(member, vldt->data) != NXT_OK)
{
return NXT_ERROR;
}
break;
}
}
}
static nxt_int_t
nxt_conf_vldt_object_iterator(nxt_conf_value_t *value, void *data)
{
uint32_t index;
nxt_str_t name;
nxt_conf_value_t *member;
nxt_conf_vldt_member_t validator;
validator = data;
index = 0;
for ( ;; ) {
member = nxt_conf_next_object_member(value, &name, &index);
if (member == NULL) {
return NXT_OK;
}
if (validator(&name, member) != NXT_OK) {
return NXT_ERROR;
}
}
return NXT_OK;
}

View File

@@ -88,7 +88,7 @@ nxt_controller_start(nxt_task_t *task, nxt_runtime_t *rt)
nxt_http_fields_hash_t *hash; nxt_http_fields_hash_t *hash;
static const nxt_str_t json static const nxt_str_t json
= nxt_string("{ \"sockets\": {}, \"applications\": {} }"); = nxt_string("{ \"listeners\": {}, \"applications\": {} }");
hash = nxt_http_fields_hash_create(nxt_controller_request_fields, hash = nxt_http_fields_hash_create(nxt_controller_request_fields,
rt->mem_pool); rt->mem_pool);
@@ -593,6 +593,7 @@ nxt_controller_process_request(nxt_task_t *task, nxt_conn_t *c,
if (value == NULL) { if (value == NULL) {
nxt_mp_destroy(mp); nxt_mp_destroy(mp);
status = 400; status = 400;
nxt_str_set(&resp.json, "{ \"error\": \"Invalid JSON.\" }");
goto done; goto done;
} }
@@ -620,6 +621,13 @@ nxt_controller_process_request(nxt_task_t *task, nxt_conn_t *c,
} }
} }
if (nxt_slow_path(nxt_conf_validate(value) != NXT_OK)) {
status = 400;
nxt_str_set(&resp.json,
"{ \"error\": \"Invalid configuration.\" }");
goto done;
}
nxt_mp_destroy(nxt_controller_conf.pool); nxt_mp_destroy(nxt_controller_conf.pool);
nxt_controller_conf.root = value; nxt_controller_conf.root = value;
@@ -674,6 +682,13 @@ nxt_controller_process_request(nxt_task_t *task, nxt_conn_t *c,
goto done; goto done;
} }
if (nxt_slow_path(nxt_conf_validate(value) != NXT_OK)) {
status = 400;
nxt_str_set(&resp.json,
"{ \"error\": \"Invalid configuration.\" }");
goto done;
}
nxt_mp_destroy(nxt_controller_conf.pool); nxt_mp_destroy(nxt_controller_conf.pool);
nxt_controller_conf.root = value; nxt_controller_conf.root = value;
@@ -697,7 +712,6 @@ done:
case 400: case 400:
nxt_str_set(&resp.status_line, "400 Bad Request"); nxt_str_set(&resp.status_line, "400 Bad Request");
nxt_str_set(&resp.json, "{ \"error\": \"Invalid JSON.\" }");
break; break;
case 404: case 404: