summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorValentin Bartenev <vbart@nginx.com>2017-07-05 18:44:43 +0300
committerValentin Bartenev <vbart@nginx.com>2017-07-05 18:44:43 +0300
commit842aa9ab46ec5e065ac55b1d186ef9ea81c14af4 (patch)
treeb6504a70fa739bd082d1ae7a583b35e0a827baa4
parent4fe5d22dcc5d6e42c5faa6fe06dd076cde799324 (diff)
downloadunit-842aa9ab46ec5e065ac55b1d186ef9ea81c14af4.tar.gz
unit-842aa9ab46ec5e065ac55b1d186ef9ea81c14af4.tar.bz2
Configuration: basic validation of schema.
Diffstat (limited to '')
-rw-r--r--auto/sources1
-rw-r--r--src/nxt_conf.c136
-rw-r--r--src/nxt_conf.h13
-rw-r--r--src/nxt_conf_validation.c173
-rw-r--r--src/nxt_controller.c18
5 files changed, 288 insertions, 53 deletions
diff --git a/auto/sources b/auto/sources
index d8403ada..04cc6297 100644
--- a/auto/sources
+++ b/auto/sources
@@ -139,6 +139,7 @@ NXT_LIB_SRCS=" \
src/nxt_app_log.c \
src/nxt_runtime.c \
src/nxt_conf.c \
+ src/nxt_conf_validation.c \
src/nxt_stream_module.c \
src/nxt_master_process.c \
src/nxt_worker_process.c \
diff --git a/src/nxt_conf.c b/src/nxt_conf.c
index 0ae5d816..d162a80c 100644
--- a/src/nxt_conf.c
+++ b/src/nxt_conf.c
@@ -17,15 +17,15 @@
typedef enum {
- NXT_CONF_NULL = 0,
- NXT_CONF_BOOLEAN,
- NXT_CONF_INTEGER,
- NXT_CONF_NUMBER,
- NXT_CONF_SHORT_STRING,
- NXT_CONF_STRING,
- NXT_CONF_ARRAY,
- NXT_CONF_OBJECT,
-} nxt_conf_type_t;
+ NXT_CONF_VALUE_NULL = 0,
+ NXT_CONF_VALUE_BOOLEAN,
+ NXT_CONF_VALUE_INTEGER,
+ NXT_CONF_VALUE_NUMBER,
+ NXT_CONF_VALUE_SHORT_STRING,
+ NXT_CONF_VALUE_STRING,
+ NXT_CONF_VALUE_ARRAY,
+ NXT_CONF_VALUE_OBJECT,
+} nxt_conf_value_type_t;
typedef enum {
@@ -51,7 +51,7 @@ struct nxt_conf_value_s {
nxt_conf_object_t *object;
} 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_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->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 {
u_char *start;
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_member_t *member;
- if (value->type != NXT_CONF_OBJECT) {
+ if (value->type != NXT_CONF_VALUE_OBJECT) {
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);
- if (v == NULL || v->type == NXT_CONF_NULL) {
+ if (v == NULL || v->type == NXT_CONF_VALUE_NULL) {
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:
- if (v->type != NXT_CONF_BOOLEAN) {
+ if (v->type != NXT_CONF_VALUE_BOOLEAN) {
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_MSEC:
- if (v->type != NXT_CONF_INTEGER) {
+ if (v->type != NXT_CONF_VALUE_INTEGER) {
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:
- if (v->type == NXT_CONF_NUMBER) {
+ if (v->type == NXT_CONF_VALUE_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;
} 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:
- if (v->type != NXT_CONF_SHORT_STRING
- && v->type != NXT_CONF_STRING)
+ if (v->type != NXT_CONF_VALUE_SHORT_STRING
+ && v->type != NXT_CONF_VALUE_STRING)
{
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_member_t *member;
- if (value->type != NXT_CONF_OBJECT) {
+ if (value->type != NXT_CONF_VALUE_OBJECT) {
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.type = NXT_CONF_STRING;
+ member->name.type = NXT_CONF_VALUE_STRING;
} else {
member->name.u.str[0] = 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;
@@ -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_uint_t n;
- if (op != NULL && src->type != NXT_CONF_OBJECT) {
+ if (op != NULL && src->type != NXT_CONF_VALUE_OBJECT) {
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) {
- case NXT_CONF_STRING:
+ case NXT_CONF_VALUE_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;
- case NXT_CONF_ARRAY:
+ case NXT_CONF_VALUE_ARRAY:
size = sizeof(nxt_conf_array_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;
- case NXT_CONF_OBJECT:
+ case NXT_CONF_VALUE_OBJECT:
return nxt_conf_copy_object(mp, op, dst, src);
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))
{
value->u.boolean = 1;
- value->type = NXT_CONF_BOOLEAN;
+ value->type = NXT_CONF_VALUE_BOOLEAN;
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))
{
value->u.boolean = 0;
- value->type = NXT_CONF_BOOLEAN;
+ value->type = NXT_CONF_VALUE_BOOLEAN;
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
&& nxt_memcmp(start, "null", 4) == 0))
{
- value->type = NXT_CONF_NULL;
+ value->type = NXT_CONF_VALUE_NULL;
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->type = NXT_CONF_OBJECT;
+ value->type = NXT_CONF_VALUE_OBJECT;
object->count = count;
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->type = NXT_CONF_ARRAY;
+ value->type = NXT_CONF_VALUE_ARRAY;
array->count = count;
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;
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);
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;
} else {
- value->type = NXT_CONF_SHORT_STRING;
+ value->type = NXT_CONF_VALUE_SHORT_STRING;
value->u.str[0] = size;
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 != '.') {
- value->type = NXT_CONF_INTEGER;
+ value->type = NXT_CONF_VALUE_INTEGER;
value->u.integer = sign * integer;
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;
}
- value->type = NXT_CONF_NUMBER;
+ value->type = NXT_CONF_VALUE_NUMBER;
value->u.number = integer + (double) frac / power;
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) {
- case NXT_CONF_NULL:
+ case NXT_CONF_VALUE_NULL:
return sizeof("null") - 1;
- case NXT_CONF_BOOLEAN:
+ case NXT_CONF_VALUE_BOOLEAN:
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);
- case NXT_CONF_NUMBER:
+ case NXT_CONF_VALUE_NUMBER:
/* TODO */
return 0;
- case NXT_CONF_SHORT_STRING:
- case NXT_CONF_STRING:
+ case NXT_CONF_VALUE_SHORT_STRING:
+ case NXT_CONF_VALUE_STRING:
return nxt_conf_json_string_length(value);
- case NXT_CONF_ARRAY:
+ case NXT_CONF_VALUE_ARRAY:
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);
}
@@ -1499,28 +1533,28 @@ nxt_conf_json_print(u_char *p, nxt_conf_value_t *value,
{
switch (value->type) {
- case NXT_CONF_NULL:
+ case NXT_CONF_VALUE_NULL:
return nxt_cpymem(p, "null", 4);
- case NXT_CONF_BOOLEAN:
+ case NXT_CONF_VALUE_BOOLEAN:
return value->u.boolean ? nxt_cpymem(p, "true", 4)
: nxt_cpymem(p, "false", 5);
- case NXT_CONF_INTEGER:
+ case NXT_CONF_VALUE_INTEGER:
return nxt_conf_json_print_integer(p, value);
- case NXT_CONF_NUMBER:
+ case NXT_CONF_VALUE_NUMBER:
/* TODO */
return p;
- case NXT_CONF_SHORT_STRING:
- case NXT_CONF_STRING:
+ case NXT_CONF_VALUE_SHORT_STRING:
+ case NXT_CONF_VALUE_STRING:
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);
- case NXT_CONF_OBJECT:
+ case NXT_CONF_VALUE_OBJECT:
return nxt_conf_json_print_object(p, value, pretty);
}
diff --git a/src/nxt_conf.h b/src/nxt_conf.h
index 45d5ece4..64997b56 100644
--- a/src/nxt_conf.h
+++ b/src/nxt_conf.h
@@ -9,6 +9,15 @@
#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_op_s nxt_conf_op_t;
@@ -40,6 +49,8 @@ typedef struct {
} 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_object_member(nxt_conf_value_t *value,
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,
nxt_conf_json_pretty_t *pretty);
+nxt_int_t nxt_conf_validate(nxt_conf_value_t *value);
+
#endif /* _NXT_CONF_INCLUDED_ */
diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c
new file mode 100644
index 00000000..fd92020b
--- /dev/null
+++ b/src/nxt_conf_validation.c
@@ -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;
+}
diff --git a/src/nxt_controller.c b/src/nxt_controller.c
index a3c0af17..757c294d 100644
--- a/src/nxt_controller.c
+++ b/src/nxt_controller.c
@@ -88,7 +88,7 @@ nxt_controller_start(nxt_task_t *task, nxt_runtime_t *rt)
nxt_http_fields_hash_t *hash;
static const nxt_str_t json
- = nxt_string("{ \"sockets\": {}, \"applications\": {} }");
+ = nxt_string("{ \"listeners\": {}, \"applications\": {} }");
hash = nxt_http_fields_hash_create(nxt_controller_request_fields,
rt->mem_pool);
@@ -593,6 +593,7 @@ nxt_controller_process_request(nxt_task_t *task, nxt_conn_t *c,
if (value == NULL) {
nxt_mp_destroy(mp);
status = 400;
+ nxt_str_set(&resp.json, "{ \"error\": \"Invalid JSON.\" }");
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_controller_conf.root = value;
@@ -674,6 +682,13 @@ nxt_controller_process_request(nxt_task_t *task, nxt_conn_t *c,
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_controller_conf.root = value;
@@ -697,7 +712,6 @@ done:
case 400:
nxt_str_set(&resp.status_line, "400 Bad Request");
- nxt_str_set(&resp.json, "{ \"error\": \"Invalid JSON.\" }");
break;
case 404: