summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorValentin Bartenev <vbart@nginx.com>2017-04-11 00:29:47 +0300
committerValentin Bartenev <vbart@nginx.com>2017-04-11 00:29:47 +0300
commitcddbab63129dcffee4099453e304e67ecf8b6c04 (patch)
treea1de766b897992b044e4155d402bd9bfde1596bb /src
parent6af2d1cfc601c150bf67e646f4b5249b7c29a30e (diff)
downloadunit-cddbab63129dcffee4099453e304e67ecf8b6c04.tar.gz
unit-cddbab63129dcffee4099453e304e67ecf8b6c04.tar.bz2
JSON output in controller.
Diffstat (limited to '')
-rw-r--r--src/nxt_conf.h2
-rw-r--r--src/nxt_conf_json.c329
-rw-r--r--src/nxt_controller.c67
3 files changed, 384 insertions, 14 deletions
diff --git a/src/nxt_conf.h b/src/nxt_conf.h
index 5d29419a..1d08199c 100644
--- a/src/nxt_conf.h
+++ b/src/nxt_conf.h
@@ -14,6 +14,8 @@ 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);
+nxt_buf_t *nxt_conf_json_print(nxt_conf_json_value_t *value,
+ nxt_mem_pool_t *pool);
#endif /* _NXT_CONF_INCLUDED_ */
diff --git a/src/nxt_conf_json.c b/src/nxt_conf_json.c
index cf0190f4..109edf22 100644
--- a/src/nxt_conf_json.c
+++ b/src/nxt_conf_json.c
@@ -69,6 +69,20 @@ 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 uintptr_t nxt_conf_json_print_value(u_char *pos,
+ nxt_conf_json_value_t *value);
+static uintptr_t nxt_conf_json_print_integer(u_char *pos,
+ nxt_conf_json_value_t *value);
+static uintptr_t nxt_conf_json_print_string(u_char *pos,
+ nxt_conf_json_value_t *value);
+static uintptr_t nxt_conf_json_print_array(u_char *pos,
+ nxt_conf_json_value_t *value);
+static uintptr_t nxt_conf_json_print_object(u_char *pos,
+ nxt_conf_json_value_t *value);
+
+static uintptr_t nxt_conf_json_escape(u_char *dst, u_char *src, size_t size);
+
+
static const nxt_lvlhsh_proto_t nxt_conf_json_object_hash_proto
nxt_aligned(64) =
{
@@ -774,3 +788,318 @@ nxt_conf_json_parse_number(u_char *pos, u_char *end,
return NULL;
}
+
+
+nxt_buf_t *
+nxt_conf_json_print(nxt_conf_json_value_t *value, nxt_mem_pool_t *pool)
+{
+ size_t size;
+ nxt_buf_t *b;
+
+ size = nxt_conf_json_print_value(NULL, value);
+
+ b = nxt_buf_mem_alloc(pool, size, 0);
+ if (nxt_slow_path(b == NULL)) {
+ return NULL;
+ }
+
+ b->mem.free = (u_char *) nxt_conf_json_print_value(b->mem.free, value);
+
+ return b;
+}
+
+
+static uintptr_t
+nxt_conf_json_print_value(u_char *pos, nxt_conf_json_value_t *value)
+{
+ static const u_char null[4] = "null";
+ static const u_char true[4] = "true";
+ static const u_char false[5] = "false";
+
+ switch (value->type) {
+
+ case NXT_CONF_JSON_NULL:
+
+ if (pos == NULL) {
+ return sizeof(null);
+ }
+
+ return (uintptr_t) nxt_cpymem(pos, null, sizeof(null));
+
+ case NXT_CONF_JSON_BOOLEAN:
+
+ if (pos == NULL) {
+ return value->u.boolean ? 4 : 5;
+ }
+
+ if (value->u.boolean) {
+ return (uintptr_t) nxt_cpymem(pos, true, sizeof(true));
+ }
+
+ return (uintptr_t) nxt_cpymem(pos, false, sizeof(false));
+
+ case NXT_CONF_JSON_INTEGER:
+ return nxt_conf_json_print_integer(pos, value);
+
+ case NXT_CONF_JSON_NUMBER:
+ /* TODO */
+ return (pos == NULL) ? 0 : (uintptr_t) pos;
+
+ case NXT_CONF_JSON_SHORT_STRING:
+ case NXT_CONF_JSON_STRING:
+ return nxt_conf_json_print_string(pos, value);
+
+ case NXT_CONF_JSON_ARRAY:
+ return nxt_conf_json_print_array(pos, value);
+
+ case NXT_CONF_JSON_OBJECT:
+ return nxt_conf_json_print_object(pos, value);
+ }
+
+ nxt_unreachable();
+
+ return (pos == NULL) ? 0 : (uintptr_t) pos;
+}
+
+
+static uintptr_t
+nxt_conf_json_print_integer(u_char *pos, nxt_conf_json_value_t *value)
+{
+ int64_t num;
+
+ num = value->u.integer;
+
+ if (pos == NULL) {
+ num = llabs(num);
+
+ if (num <= 9999) {
+ return sizeof("-9999") - 1;
+ }
+
+ if (num <= 99999999999) {
+ return sizeof("-99999999999") - 1;
+ }
+
+ return NXT_INT64_T_LEN;
+ }
+
+ return (uintptr_t) nxt_sprintf(pos, pos + NXT_INT64_T_LEN, "%L", num);
+}
+
+
+static uintptr_t
+nxt_conf_json_print_string(u_char *pos, nxt_conf_json_value_t *value)
+{
+ size_t len;
+ u_char *s;
+
+ if (value->type == NXT_CONF_JSON_SHORT_STRING) {
+ len = value->u.str[0];
+ s = &value->u.str[1];
+
+ } else {
+ len = value->u.string->length;
+ s = value->u.string->start;
+ }
+
+ if (pos == NULL) {
+ return 2 + len + nxt_conf_json_escape(NULL, s, len);
+ }
+
+ *pos++ = '"';
+
+ pos = (u_char *) nxt_conf_json_escape(pos, s, len);
+
+ *pos++ = '"';
+
+ return (uintptr_t) pos;
+}
+
+
+static uintptr_t
+nxt_conf_json_print_array(u_char *pos, nxt_conf_json_value_t *value)
+{
+ size_t len;
+ uint32_t n;
+ nxt_array_t *array;
+
+ array = value->u.array;
+
+ if (pos == NULL) {
+ len = 2;
+
+ value = array->elts;
+
+ for (n = 0; n < array->nelts; n++) {
+ len += nxt_conf_json_print_value(NULL, &value[n]);
+ }
+
+ return n + len;
+ }
+
+ *pos++ = '[';
+
+ if (array->nelts != 0) {
+ value = array->elts;
+
+ pos = (u_char *) nxt_conf_json_print_value(pos, &value[0]);
+
+ for (n = 1; n < array->nelts; n++) {
+ *pos++ = ',';
+ pos = (u_char *) nxt_conf_json_print_value(pos, &value[n]);
+ }
+ }
+
+ *pos++ = ']';
+
+ return (uintptr_t) pos;
+}
+
+
+static uintptr_t
+nxt_conf_json_print_object(u_char *pos, nxt_conf_json_value_t *value)
+{
+ size_t len;
+ nxt_lvlhsh_t *object;
+ nxt_lvlhsh_each_t lhe;
+ nxt_conf_json_obj_member_t *member;
+
+ nxt_memzero(&lhe, sizeof(nxt_lvlhsh_each_t));
+
+ lhe.proto = &nxt_conf_json_object_hash_proto;
+
+ object = value->u.object;
+
+ if (pos == NULL) {
+ len = 2;
+
+ for ( ;; ) {
+ member = nxt_lvlhsh_each(object, &lhe);
+
+ if (member == NULL) {
+ break;
+ }
+
+ len += nxt_conf_json_print_string(NULL, &member->name) + 1
+ + nxt_conf_json_print_value(NULL, &member->value) + 1;
+ }
+
+ return len;
+ }
+
+ *pos++ = '{';
+
+ member = nxt_lvlhsh_each(object, &lhe);
+
+ if (member != NULL) {
+
+ for ( ;; ) {
+ pos = (u_char *) nxt_conf_json_print_string(pos, &member->name);
+
+ *pos++ = ':';
+
+ pos = (u_char *) nxt_conf_json_print_value(pos, &member->value);
+
+ member = nxt_lvlhsh_each(object, &lhe);
+
+ if (member == NULL) {
+ break;
+ }
+
+ *pos++ = ',';
+ }
+ }
+
+ *pos++ = '}';
+
+ return (uintptr_t) pos;
+}
+
+
+static uintptr_t
+nxt_conf_json_escape(u_char *dst, u_char *src, size_t size)
+{
+ u_char ch;
+ size_t len;
+
+ if (dst == NULL) {
+ len = 0;
+
+ while (size) {
+ ch = *src++;
+
+ if (ch == '\\' || ch == '"') {
+ len++;
+
+ } else if (ch <= 0x1f) {
+
+ switch (ch) {
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\b':
+ case '\f':
+ len++;
+ break;
+
+ default:
+ len += sizeof("\\u001F") - 2;
+ }
+ }
+
+ size--;
+ }
+
+ return len;
+ }
+
+ while (size) {
+ ch = *src++;
+
+ if (ch > 0x1f) {
+
+ if (ch == '\\' || ch == '"') {
+ *dst++ = '\\';
+ }
+
+ *dst++ = ch;
+
+ } else {
+ *dst++ = '\\';
+
+ switch (ch) {
+ case '\n':
+ *dst++ = 'n';
+ break;
+
+ case '\r':
+ *dst++ = 'r';
+ break;
+
+ case '\t':
+ *dst++ = 't';
+ break;
+
+ case '\b':
+ *dst++ = 'b';
+ break;
+
+ case '\f':
+ *dst++ = 'f';
+ break;
+
+ default:
+ *dst++ = 'u'; *dst++ = '0'; *dst++ = '0';
+ *dst++ = '0' + (ch >> 4);
+
+ ch &= 0xf;
+
+ *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10);
+ }
+ }
+
+ size--;
+ }
+
+ return (uintptr_t) dst;
+}
diff --git a/src/nxt_controller.c b/src/nxt_controller.c
index e4ca0669..901a8875 100644
--- a/src/nxt_controller.c
+++ b/src/nxt_controller.c
@@ -14,6 +14,8 @@
typedef struct {
nxt_http_request_parse_t parser;
size_t length;
+
+ nxt_conf_json_value_t *conf;
} nxt_controller_request_t;
@@ -41,7 +43,9 @@ 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_task_t *task,
- nxt_event_conn_t *c);
+ nxt_event_conn_t *c, nxt_controller_request_t *r);
+static void nxt_controller_conf_output(nxt_task_t *task, nxt_event_conn_t *c,
+ nxt_controller_request_t *r);
static nxt_http_fields_t nxt_controller_request_fields[] = {
@@ -513,29 +517,28 @@ static void
nxt_controller_process_request(nxt_task_t *task, nxt_event_conn_t *c,
nxt_controller_request_t *r)
{
- nxt_str_t response;
nxt_buf_t *b;
- static const u_char response_good[]
- = "HTTP/1.0 200 OK\r\n\r\ndone\r\n";
+ static const nxt_str_t resp418
+ = nxt_string("HTTP/1.0 418 I'm a teapot\r\n\r\nerror\r\n");
- static const u_char response_bad[]
- = "HTTP/1.0 418 I'm a teapot\r\n\r\nerror\r\n";
+ if (nxt_controller_request_body_parse(task, c, r) != NXT_OK) {
+ goto error;
+ }
- if (nxt_controller_request_body_parse(task, c) == NXT_OK) {
- nxt_str_set(&response, response_good);
+ nxt_controller_conf_output(task, c, r);
- } else {
- nxt_str_set(&response, response_bad);
- }
+ return;
- b = nxt_buf_mem_alloc(c->mem_pool, response.length, 0);
+error:
+
+ b = nxt_buf_mem_alloc(c->mem_pool, resp418.length, 0);
if (nxt_slow_path(b == NULL)) {
nxt_controller_conn_close(task, c, r);
return;
}
- b->mem.free = nxt_cpymem(b->mem.free, response.start, response.length);
+ b->mem.free = nxt_cpymem(b->mem.free, resp418.start, resp418.length);
c->write = b;
c->write_state = &nxt_controller_conn_write_state;
@@ -545,7 +548,8 @@ nxt_controller_process_request(nxt_task_t *task, nxt_event_conn_t *c,
static nxt_int_t
-nxt_controller_request_body_parse(nxt_task_t *task, nxt_event_conn_t *c)
+nxt_controller_request_body_parse(nxt_task_t *task, nxt_event_conn_t *c,
+ nxt_controller_request_t *r)
{
nxt_buf_t *b;
nxt_conf_json_value_t *value;
@@ -558,5 +562,40 @@ nxt_controller_request_body_parse(nxt_task_t *task, nxt_event_conn_t *c)
return NXT_ERROR;
}
+ r->conf = value;
+
return NXT_OK;
}
+
+
+static void
+nxt_controller_conf_output(nxt_task_t *task, nxt_event_conn_t *c,
+ nxt_controller_request_t *r)
+{
+ nxt_buf_t *b;
+
+ static const nxt_str_t head = nxt_string("HTTP/1.0 200 OK\r\n\r\n");
+
+ b = nxt_buf_mem_alloc(c->mem_pool, head.length, 0);
+ if (nxt_slow_path(b == NULL)) {
+ nxt_controller_conn_close(task, c, r);
+ return;
+ }
+
+ b->mem.free = nxt_cpymem(b->mem.free, head.start, head.length);
+
+ c->write = b;
+
+ b = nxt_conf_json_print(r->conf, c->mem_pool);
+
+ if (b == NULL) {
+ nxt_controller_conn_close(task, c, r);
+ return;
+ }
+
+ c->write->next = b;
+ c->write_state = &nxt_controller_conn_write_state;
+
+ nxt_event_conn_write(task->thread->engine, c);
+ return;
+}