summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nxt_conf.h19
-rw-r--r--src/nxt_conf_json.c772
-rw-r--r--src/nxt_controller.c44
3 files changed, 821 insertions, 14 deletions
diff --git a/src/nxt_conf.h b/src/nxt_conf.h
new file mode 100644
index 00000000..5d29419a
--- /dev/null
+++ b/src/nxt_conf.h
@@ -0,0 +1,19 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Valentin V. Bartenev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#ifndef _NXT_CONF_INCLUDED_
+#define _NXT_CONF_INCLUDED_
+
+
+typedef struct nxt_conf_json_value_s nxt_conf_json_value_t;
+
+
+nxt_conf_json_value_t *nxt_conf_json_parse(nxt_buf_mem_t *b,
+ nxt_mem_pool_t *pool);
+
+
+#endif /* _NXT_CONF_INCLUDED_ */
diff --git a/src/nxt_conf_json.c b/src/nxt_conf_json.c
new file mode 100644
index 00000000..5f181611
--- /dev/null
+++ b/src/nxt_conf_json.c
@@ -0,0 +1,772 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Valentin V. Bartenev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#include <nxt_main.h>
+#include <nxt_conf.h>
+#if 0
+#include <math.h>
+#include <float.h>
+#endif
+
+
+typedef enum {
+ NXT_CONF_JSON_NULL = 0,
+ NXT_CONF_JSON_BOOLEAN,
+ NXT_CONF_JSON_INTEGER,
+ NXT_CONF_JSON_NUMBER,
+ NXT_CONF_JSON_SHORT_STRING,
+ NXT_CONF_JSON_STRING,
+ NXT_CONF_JSON_ARRAY,
+ NXT_CONF_JSON_OBJECT,
+} nxt_conf_json_type_t;
+
+
+struct nxt_conf_json_value_s {
+ union {
+ uint32_t boolean; /* 1 bit. */
+ int64_t integer;
+ /* double number; */
+ u_char str[15];
+ nxt_str_t *string;
+ nxt_lvlhsh_t *object;
+ nxt_array_t *array;
+ } u;
+
+ nxt_conf_json_type_t type:8; /* 3 bits. */
+};
+
+
+typedef struct {
+ nxt_conf_json_value_t name;
+ nxt_conf_json_value_t value;
+} nxt_conf_json_obj_member_t;
+
+
+static nxt_int_t nxt_conf_json_object_hash_test(nxt_lvlhsh_query_t *lhq,
+ void *data);
+static nxt_int_t nxt_conf_json_object_member_add(nxt_lvlhsh_t *lvlhsh,
+ nxt_conf_json_obj_member_t *member, nxt_mem_pool_t *pool);
+#if 0
+static nxt_conf_json_value_t *nxt_conf_json_object_member_get(
+ nxt_lvlhsh_t *lvlhsh, u_char *name, size_t length);
+#endif
+
+
+static u_char *nxt_conf_json_skip_space(u_char *pos, u_char *end);
+static u_char *nxt_conf_json_parse_value(u_char *pos, u_char *end,
+ nxt_conf_json_value_t *value, nxt_mem_pool_t *pool);
+static u_char *nxt_conf_json_parse_object(u_char *pos, u_char *end,
+ nxt_conf_json_value_t *value, nxt_mem_pool_t *pool);
+static u_char *nxt_conf_json_parse_array(u_char *pos, u_char *end,
+ nxt_conf_json_value_t *value, nxt_mem_pool_t *pool);
+static u_char *nxt_conf_json_parse_string(u_char *pos, u_char *end,
+ nxt_conf_json_value_t *value, nxt_mem_pool_t *pool);
+static u_char *nxt_conf_json_parse_number(u_char *pos, u_char *end,
+ nxt_conf_json_value_t *value, nxt_mem_pool_t *pool);
+
+
+static const nxt_lvlhsh_proto_t nxt_conf_json_object_hash_proto
+ nxt_aligned(64) =
+{
+ NXT_LVLHSH_DEFAULT,
+ 0,
+ nxt_conf_json_object_hash_test,
+ nxt_lvlhsh_pool_alloc,
+ nxt_lvlhsh_pool_free,
+};
+
+
+static nxt_int_t
+nxt_conf_json_object_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
+{
+ nxt_conf_json_value_t *name;
+
+ name = &((nxt_conf_json_obj_member_t *) data)->name;
+
+ if (name->type == NXT_CONF_JSON_SHORT_STRING) {
+
+ if (nxt_str_eq(&lhq->key, &name->u.str[1], name->u.str[0])) {
+ return NXT_OK;
+ }
+
+ } else {
+
+ if (nxt_strstr_eq(&lhq->key, name->u.string)) {
+ return NXT_OK;
+ }
+ }
+
+ return NXT_DECLINED;
+}
+
+
+static nxt_int_t
+nxt_conf_json_object_member_add(nxt_lvlhsh_t *lvlhsh,
+ nxt_conf_json_obj_member_t *member, nxt_mem_pool_t *pool)
+{
+ nxt_lvlhsh_query_t lhq;
+ nxt_conf_json_value_t *name;
+
+ name = &member->name;
+
+ if (name->type == NXT_CONF_JSON_SHORT_STRING) {
+ lhq.key.length = name->u.str[0];
+ lhq.key.start = &name->u.str[1];
+
+ } else {
+ lhq.key = *name->u.string;
+ }
+
+ lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
+ lhq.replace = 0;
+ lhq.value = member;
+ lhq.proto = &nxt_conf_json_object_hash_proto;
+ lhq.pool = pool;
+
+ return nxt_lvlhsh_insert(lvlhsh, &lhq);
+}
+
+
+#if 0
+static nxt_conf_json_value_t *
+nxt_conf_json_object_member_get(nxt_lvlhsh_t *lvlhsh, u_char *name,
+ size_t length)
+{
+ nxt_lvlhsh_query_t lhq;
+ nxt_conf_json_obj_member_t *member;
+
+ lhq.key_hash = nxt_djb_hash(name, length);
+ lhq.key.length = length;
+ lhq.key.start = name;
+ lhq.proto = &nxt_conf_json_object_hash_proto;
+
+ if (nxt_fast_path(nxt_lvlhsh_find(lvlhsh, &lhq) == NXT_OK)) {
+ member = lhq.value;
+ return &member->value;
+ }
+
+ return NULL;
+}
+#endif
+
+
+nxt_conf_json_value_t *
+nxt_conf_json_parse(nxt_buf_mem_t *b, nxt_mem_pool_t *pool)
+{
+ u_char *pos, *end;
+ nxt_conf_json_value_t *value;
+
+ value = nxt_mem_alloc(pool, sizeof(nxt_conf_json_value_t));
+ if (nxt_slow_path(value == NULL)) {
+ return NULL;
+ }
+
+ pos = b->pos;
+ end = b->free;
+
+ pos = nxt_conf_json_skip_space(pos, end);
+
+ if (nxt_slow_path(pos == end)) {
+ return NULL;
+ }
+
+ pos = nxt_conf_json_parse_value(pos, end, value, pool);
+
+ if (nxt_slow_path(pos == NULL)) {
+ return NULL;
+ }
+
+ pos = nxt_conf_json_skip_space(pos, end);
+
+ if (nxt_slow_path(pos != end)) {
+ return NULL;
+ }
+
+ return value;
+}
+
+
+static u_char *
+nxt_conf_json_skip_space(u_char *pos, u_char *end)
+{
+ for ( /* void */ ; nxt_fast_path(pos != end); pos++) {
+
+ switch (*pos) {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ continue;
+ }
+
+ break;
+ }
+
+ return pos;
+}
+
+
+static u_char *
+nxt_conf_json_parse_value(u_char *pos, u_char *end,
+ nxt_conf_json_value_t *value, nxt_mem_pool_t *pool)
+{
+ u_char ch;
+
+ ch = *pos;
+
+ switch (ch) {
+ case '{':
+ return nxt_conf_json_parse_object(pos, end, value, pool);
+
+ case '[':
+ return nxt_conf_json_parse_array(pos, end, value, pool);
+
+ case '"':
+ return nxt_conf_json_parse_string(pos, end, value, pool);
+
+ case 't':
+ if (nxt_fast_path(end - pos >= 4
+ || nxt_memcmp(pos, (u_char *) "true", 4) == 0))
+ {
+ value->u.boolean = 1;
+ value->type = NXT_CONF_JSON_BOOLEAN;
+
+ return pos + 4;
+ }
+
+ return NULL;
+
+ case 'f':
+ if (nxt_fast_path(end - pos >= 5
+ || nxt_memcmp(pos, (u_char *) "false", 5) == 0))
+ {
+ value->u.boolean = 0;
+ value->type = NXT_CONF_JSON_BOOLEAN;
+
+ return pos + 5;
+ }
+
+ return NULL;
+
+ case 'n':
+ if (nxt_fast_path(end - pos >= 4
+ || nxt_memcmp(pos, (u_char *) "null", 4) == 0))
+ {
+ value->type = NXT_CONF_JSON_NULL;
+ return pos + 4;
+ }
+
+ return NULL;
+ }
+
+ if (nxt_fast_path(ch == '-' || (ch - '0') <= 9)) {
+ return nxt_conf_json_parse_number(pos, end, value, pool);
+ }
+
+ return NULL;
+}
+
+
+static u_char *
+nxt_conf_json_parse_object(u_char *pos, u_char *end,
+ nxt_conf_json_value_t *value, nxt_mem_pool_t *pool)
+{
+ nxt_int_t rc;
+ nxt_lvlhsh_t *object;
+ nxt_conf_json_obj_member_t *member;
+
+ object = nxt_mem_zalloc(pool, sizeof(nxt_lvlhsh_t));
+ if (nxt_slow_path(object == NULL)) {
+ return NULL;
+ }
+
+ value->type = NXT_CONF_JSON_OBJECT;
+ value->u.object = object;
+
+ pos = nxt_conf_json_skip_space(pos + 1, end);
+
+ if (nxt_slow_path(pos == end)) {
+ return NULL;
+ }
+
+ if (*pos != '}') {
+
+ for ( ;; ) {
+ if (*pos != '"') {
+ return NULL;
+ }
+
+ member = nxt_mem_alloc(pool, sizeof(nxt_conf_json_obj_member_t));
+ if (nxt_slow_path(member == NULL)) {
+ return NULL;
+ }
+
+ pos = nxt_conf_json_parse_string(pos, end, &member->name, pool);
+
+ if (nxt_slow_path(pos == NULL)) {
+ return NULL;
+ }
+
+ pos = nxt_conf_json_skip_space(pos, end);
+
+ if (nxt_slow_path(pos == end || *pos != ':')) {
+ return NULL;
+ }
+
+ pos = nxt_conf_json_skip_space(pos + 1, end);
+
+ if (nxt_slow_path(pos == end)) {
+ return NULL;
+ }
+
+ pos = nxt_conf_json_parse_value(pos, end, &member->value, pool);
+
+ if (nxt_slow_path(pos == NULL)) {
+ return NULL;
+ }
+
+ rc = nxt_conf_json_object_member_add(object, member, pool);
+
+ if (nxt_slow_path(rc != NXT_OK)) {
+ return NULL;
+ }
+
+ pos = nxt_conf_json_skip_space(pos, end);
+
+ if (nxt_slow_path(pos == end)) {
+ return NULL;
+ }
+
+ if (*pos == '}') {
+ break;
+ }
+
+ if (nxt_slow_path(*pos != ',')) {
+ return NULL;
+ }
+
+ pos = nxt_conf_json_skip_space(pos + 1, end);
+
+ if (nxt_slow_path(pos == end)) {
+ return NULL;
+ }
+ }
+ }
+
+ return pos + 1;
+}
+
+
+static u_char *
+nxt_conf_json_parse_array(u_char *pos, u_char *end,
+ nxt_conf_json_value_t *value, nxt_mem_pool_t *pool)
+{
+ nxt_array_t *array;
+
+ array = nxt_array_create(pool, 8, sizeof(nxt_conf_json_value_t));
+ if (nxt_slow_path(array == NULL)) {
+ return NULL;
+ }
+
+ value->type = NXT_CONF_JSON_ARRAY;
+ value->u.array = array;
+
+ pos = nxt_conf_json_skip_space(pos + 1, end);
+
+ if (nxt_slow_path(pos == end)) {
+ return NULL;
+ }
+
+ if (*pos != ']') {
+
+ for ( ;; ) {
+ value = nxt_array_add(array);
+ if (nxt_slow_path(value == NULL)) {
+ return NULL;
+ }
+
+ pos = nxt_conf_json_parse_value(pos, end, value, pool);
+
+ if (nxt_slow_path(pos == NULL)) {
+ return NULL;
+ }
+
+ pos = nxt_conf_json_skip_space(pos, end);
+
+ if (nxt_slow_path(pos == end)) {
+ return NULL;
+ }
+
+ if (*pos == ']') {
+ break;
+ }
+
+ if (nxt_slow_path(*pos != ',')) {
+ return NULL;
+ }
+
+ pos = nxt_conf_json_skip_space(pos + 1, end);
+
+ if (nxt_slow_path(pos == end)) {
+ return NULL;
+ }
+ }
+ }
+
+ return pos + 1;
+}
+
+
+static u_char *
+nxt_conf_json_parse_string(u_char *pos, u_char *end,
+ nxt_conf_json_value_t *value, nxt_mem_pool_t *pool)
+{
+ u_char ch, *last, *s;
+ size_t size, surplus;
+ uint32_t utf, utf_high;
+ nxt_uint_t i;
+ enum {
+ sw_usual = 0,
+ sw_escape,
+ sw_encoded1,
+ sw_encoded2,
+ sw_encoded3,
+ sw_encoded4,
+ } state;
+
+ pos++;
+
+ state = 0;
+ surplus = 0;
+
+ for (last = pos; last != end; last++) {
+ ch = *last;
+
+ switch (state) {
+
+ case sw_usual:
+
+ if (ch == '"') {
+ break;
+ }
+
+ if (ch == '\\') {
+ state = sw_escape;
+ continue;
+ }
+
+ if (nxt_fast_path(ch >= ' ')) {
+ continue;
+ }
+
+ return NULL;
+
+ case sw_escape:
+
+ switch (ch) {
+ case '"':
+ case '\\':
+ case '/':
+ case 'b':
+ case 'f':
+ case 'n':
+ case 'r':
+ case 't':
+ surplus++;
+ state = sw_usual;
+ continue;
+
+ case 'u':
+ /*
+ * Basic unicode 6 bytes "\uXXXX" in JSON
+ * and up to 3 bytes in UTF-8.
+ *
+ * Surrogate pair: 12 bytes "\uXXXX\uXXXX" in JSON
+ * and 3 or 4 bytes in UTF-8.
+ */
+ surplus += 3;
+ state = sw_encoded1;
+ continue;
+ }
+
+ return NULL;
+
+ case sw_encoded1:
+ case sw_encoded2:
+ case sw_encoded3:
+ case sw_encoded4:
+
+ if (nxt_fast_path((ch >= '0' && ch <= '9')
+ || (ch >= 'A' && ch <= 'F')))
+ {
+ state = (state == sw_encoded4) ? sw_usual : state + 1;
+ continue;
+ }
+
+ return NULL;
+ }
+
+ break;
+ }
+
+ if (nxt_slow_path(last == end)) {
+ return NULL;
+ }
+
+ size = last - pos - surplus;
+
+ if (size > 14) {
+ value->type = NXT_CONF_JSON_STRING;
+ value->u.string = nxt_str_alloc(pool, size);
+
+ if (nxt_slow_path(value->u.string == NULL)) {
+ return NULL;
+ }
+
+ s = value->u.string->start;
+
+ } else {
+ value->type = NXT_CONF_JSON_SHORT_STRING;
+ s = &value->u.str[1];
+ }
+
+ if (surplus == 0) {
+ nxt_memcpy(s, pos, size);
+ return last + 1;
+ }
+
+ state = 0;
+
+ do {
+ ch = *pos++;
+
+ if (ch != '\\') {
+ *s++ = ch;
+ continue;
+ }
+
+ ch = *pos++;
+
+ switch (ch) {
+ case '"':
+ case '\\':
+ case '/':
+ *s++ = ch;
+ continue;
+
+ case 'b':
+ *s++ = '\b';
+ continue;
+
+ case 'f':
+ *s++ = '\f';
+ continue;
+
+ case 'n':
+ *s++ = '\n';
+ continue;
+
+ case 'r':
+ *s++ = '\r';
+ continue;
+
+ case 't':
+ *s++ = '\t';
+ continue;
+ }
+
+ utf = 0;
+ utf_high = 0;
+
+ for ( ;; ) {
+ for (i = 0; i < 4; i++) {
+ utf = (utf << 4) + (pos[i] - (pos[i] >= 'A' ? 'A' : '0'));
+ }
+
+ pos += 4;
+
+ if (utf < 0xd800 || utf > 0xdbff || utf_high) {
+ break;
+ }
+
+ utf_high = utf;
+ utf = 0;
+
+ if (pos[0] != '\\' || pos[1] != 'u') {
+ break;
+ }
+
+ pos += 2;
+ }
+
+ if (utf_high != 0) {
+ if (nxt_slow_path(utf_high < 0xd800
+ || utf_high > 0xdbff
+ || utf < 0xdc00
+ || utf > 0xdfff))
+ {
+ /* invalid surrogate pair */
+ return NULL;
+ }
+
+ utf = ((utf_high - 0xd800) << 10) + (utf - 0xdc00);
+ }
+
+ s = nxt_utf8_encode(s, utf);
+
+ } while (pos != last);
+
+ if (size > 14) {
+ value->u.string->length = s - value->u.string->start;
+
+ } else {
+ value->u.str[0] = s - &value->u.str[1];
+ }
+
+ return pos + 1;
+}
+
+
+static u_char *
+nxt_conf_json_parse_number(u_char *pos, u_char *end,
+ nxt_conf_json_value_t *value, nxt_mem_pool_t *pool)
+{
+ u_char ch, *p;
+ uint64_t integer;
+ nxt_int_t sign;
+#if 0
+ uint64_t frac, power
+ nxt_int_t e, negative;
+#endif
+
+ static const uint64_t cutoff = NXT_INT64_T_MAX / 10;
+ static const uint64_t cutlim = NXT_INT64_T_MAX % 10;
+
+ ch = *pos;
+
+ if (ch == '-') {
+ sign = -1;
+ pos++;
+
+ } else {
+ sign = 1;
+ }
+
+ integer = 0;
+
+ for (p = pos; nxt_fast_path(p != end); p++) {
+ ch = *p;
+
+ /* Values below '0' become >= 208. */
+ ch = ch - '0';
+
+ if (ch > 9) {
+ break;
+ }
+
+ if (nxt_slow_path(integer >= cutoff
+ && (integer > cutoff || ch > cutlim)))
+ {
+ return NULL;
+ }
+
+ integer = integer * 10 + ch;
+ }
+
+ if (nxt_slow_path(p == pos || (p > pos + 1 && *pos == '0'))) {
+ return NULL;
+ }
+
+ if (ch != '.') {
+ value->type = NXT_CONF_JSON_INTEGER;
+ value->u.integer = sign * integer;
+ return p;
+ }
+
+#if 0
+ pos = p + 1;
+
+ frac = 0;
+ power = 1;
+
+ for (p = pos; nxt_fast_path(p != end); p++) {
+ ch = *p;
+
+ /* Values below '0' become >= 208. */
+ ch = ch - '0';
+
+ if (ch > 9) {
+ break;
+ }
+
+ if (nxt_slow_path((frac >= cutoff && (frac > cutoff || ch > cutlim))
+ || power > cutoff))
+ {
+ return NULL;
+ }
+
+ frac = frac * 10 + ch;
+ power *= 10;
+ }
+
+ if (nxt_slow_path(p == pos)) {
+ return NULL;
+ }
+
+ value->type = NXT_CONF_JSON_NUMBER;
+ value->u.number = integer + (double) frac / power;
+
+ value->u.number = copysign(value->u.number, sign);
+
+ if (ch == 'e' || ch == 'E') {
+ pos = p + 1;
+
+ ch = *pos;
+
+ if (ch == '-' || ch == '+') {
+ pos++;
+ }
+
+ negative = (ch == '-') ? 1 : 0;
+ e = 0;
+
+ for (p = pos; nxt_fast_path(p != end); p++) {
+ ch = *p;
+
+ /* Values below '0' become >= 208. */
+ ch = ch - '0';
+
+ if (ch > 9) {
+ break;
+ }
+
+ e = e * 10 + ch;
+
+ if (nxt_slow_path(e > DBL_MAX_10_EXP)) {
+ return NULL;
+ }
+ }
+
+ if (nxt_slow_path(p == pos)) {
+ return NULL;
+ }
+
+ if (negative) {
+ value->u.number /= exp10(e);
+
+ } else {
+ value->u.number *= exp10(e);
+ }
+ }
+
+ if (nxt_fast_path(isfinite(value->u.number))) {
+ return p;
+ }
+#endif
+
+ return NULL;
+}
diff --git a/src/nxt_controller.c b/src/nxt_controller.c
index 2c8efd09..e4ca0669 100644
--- a/src/nxt_controller.c
+++ b/src/nxt_controller.c
@@ -8,6 +8,7 @@
#include <nxt_main.h>
#include <nxt_runtime.h>
#include <nxt_master_process.h>
+#include <nxt_conf.h>
typedef struct {
@@ -39,7 +40,8 @@ static nxt_int_t nxt_controller_request_content_length(void *ctx,
static void nxt_controller_process_request(nxt_task_t *task,
nxt_event_conn_t *c, nxt_controller_request_t *r);
-static nxt_int_t nxt_controller_request_body_parse(nxt_buf_mem_t *b);
+static nxt_int_t nxt_controller_request_body_parse(nxt_task_t *task,
+ nxt_event_conn_t *c);
static nxt_http_fields_t nxt_controller_request_fields[] = {
@@ -511,27 +513,31 @@ static void
nxt_controller_process_request(nxt_task_t *task, nxt_event_conn_t *c,
nxt_controller_request_t *r)
{
- size_t size;
- nxt_buf_t *b, *wb;
+ nxt_str_t response;
+ nxt_buf_t *b;
- static const u_char response[] = "HTTP/1.0 200 OK\r\n\r\n";
+ static const u_char response_good[]
+ = "HTTP/1.0 200 OK\r\n\r\ndone\r\n";
- b = c->read;
+ static const u_char response_bad[]
+ = "HTTP/1.0 418 I'm a teapot\r\n\r\nerror\r\n";
- nxt_controller_request_body_parse(&b->mem);
+ if (nxt_controller_request_body_parse(task, c) == NXT_OK) {
+ nxt_str_set(&response, response_good);
- size = nxt_buf_mem_used_size(&b->mem);
+ } else {
+ nxt_str_set(&response, response_bad);
+ }
- wb = nxt_buf_mem_alloc(c->mem_pool, sizeof(response) - 1 + size, 0);
- if (nxt_slow_path(wb == NULL)) {
+ b = nxt_buf_mem_alloc(c->mem_pool, response.length, 0);
+ if (nxt_slow_path(b == NULL)) {
nxt_controller_conn_close(task, c, r);
return;
}
- wb->mem.free = nxt_cpymem(wb->mem.free, response, sizeof(response) - 1);
- wb->mem.free = nxt_cpymem(wb->mem.free, b->mem.pos, size);
+ b->mem.free = nxt_cpymem(b->mem.free, response.start, response.length);
- c->write = wb;
+ c->write = b;
c->write_state = &nxt_controller_conn_write_state;
nxt_event_conn_write(task->thread->engine, c);
@@ -539,8 +545,18 @@ nxt_controller_process_request(nxt_task_t *task, nxt_event_conn_t *c,
static nxt_int_t
-nxt_controller_request_body_parse(nxt_buf_mem_t *b)
+nxt_controller_request_body_parse(nxt_task_t *task, nxt_event_conn_t *c)
{
- /* TODO */
+ nxt_buf_t *b;
+ nxt_conf_json_value_t *value;
+
+ b = c->read;
+
+ value = nxt_conf_json_parse(&b->mem, c->mem_pool);
+
+ if (value == NULL) {
+ return NXT_ERROR;
+ }
+
return NXT_OK;
}