diff options
author | Valentin Bartenev <vbart@nginx.com> | 2017-04-11 00:29:47 +0300 |
---|---|---|
committer | Valentin Bartenev <vbart@nginx.com> | 2017-04-11 00:29:47 +0300 |
commit | cddbab63129dcffee4099453e304e67ecf8b6c04 (patch) | |
tree | a1de766b897992b044e4155d402bd9bfde1596bb /src | |
parent | 6af2d1cfc601c150bf67e646f4b5249b7c29a30e (diff) | |
download | unit-cddbab63129dcffee4099453e304e67ecf8b6c04.tar.gz unit-cddbab63129dcffee4099453e304e67ecf8b6c04.tar.bz2 |
JSON output in controller.
Diffstat (limited to '')
-rw-r--r-- | src/nxt_conf.h | 2 | ||||
-rw-r--r-- | src/nxt_conf_json.c | 329 | ||||
-rw-r--r-- | src/nxt_controller.c | 67 |
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; +} |