2016-07-05 17:27:30 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2016 Raphaël Monrouzeau <raphael.monrouzeau@gmail.com>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2016-07-08 18:48:41 +02:00
|
|
|
#include <limits.h>
|
2016-07-05 17:27:30 +02:00
|
|
|
#include <stdbool.h>
|
|
|
|
|
|
|
|
#include <yajl/yajl_tree.h>
|
|
|
|
#include <yajl/yajl_gen.h>
|
|
|
|
|
|
|
|
#include "kore.h"
|
|
|
|
#include "http.h"
|
|
|
|
#include "jsonrpc.h"
|
|
|
|
|
|
|
|
static void
|
|
|
|
init_log(struct jsonrpc_log *log)
|
|
|
|
{
|
|
|
|
log->msg = NULL;
|
|
|
|
log->next = log;
|
|
|
|
log->prev = log;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
append_log(struct jsonrpc_log *prev, int lvl, char *msg)
|
|
|
|
{
|
|
|
|
struct jsonrpc_log *new = kore_malloc(sizeof(struct jsonrpc_log));
|
|
|
|
|
|
|
|
new->lvl = lvl;
|
|
|
|
new->msg = msg;
|
|
|
|
|
|
|
|
new->prev = prev;
|
|
|
|
new->next = prev->next;
|
|
|
|
prev->next->prev = new;
|
|
|
|
prev->next = new;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_log(struct jsonrpc_log *root)
|
|
|
|
{
|
|
|
|
for (struct jsonrpc_log *it = root->next; it != root; it = it->next) {
|
2016-07-15 13:17:30 +02:00
|
|
|
kore_free(it);
|
2016-07-05 17:27:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
init_request(struct jsonrpc_request *req)
|
|
|
|
{
|
|
|
|
init_log(&req->log);
|
|
|
|
kore_buf_init(&req->buf, 256);
|
|
|
|
req->gen = NULL;
|
|
|
|
req->http = NULL;
|
|
|
|
req->json = NULL;
|
|
|
|
req->id = NULL;
|
|
|
|
req->method = NULL;
|
|
|
|
req->params = NULL;
|
|
|
|
req->log_levels = (1 << LOG_EMERG) | (1 << LOG_ERR) | (1 << LOG_WARNING)
|
|
|
|
| (1 << LOG_NOTICE);
|
|
|
|
req->flags = 0;
|
|
|
|
}
|
|
|
|
|
2016-07-09 12:21:03 +02:00
|
|
|
void
|
|
|
|
jsonrpc_destroy_request(struct jsonrpc_request *req)
|
2016-07-05 17:27:30 +02:00
|
|
|
{
|
|
|
|
if (req->gen != NULL) {
|
|
|
|
yajl_gen_free(req->gen);
|
|
|
|
req->gen = NULL;
|
|
|
|
}
|
|
|
|
if (req->json != NULL) {
|
|
|
|
yajl_tree_free(req->json);
|
|
|
|
req->json = NULL;
|
|
|
|
}
|
2016-07-15 13:17:30 +02:00
|
|
|
kore_buf_cleanup(&req->buf);
|
2016-07-05 17:27:30 +02:00
|
|
|
free_log(&req->log);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
jsonrpc_log(struct jsonrpc_request *req, int lvl, const char *fmt, ...)
|
|
|
|
{
|
2016-07-09 15:14:03 +02:00
|
|
|
va_list ap;
|
|
|
|
char *msg;
|
|
|
|
size_t start = req->buf.offset;
|
2016-07-05 17:27:30 +02:00
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
kore_buf_appendv(&req->buf, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
msg = kore_buf_stringify(&req->buf, NULL) + start;
|
|
|
|
|
|
|
|
append_log(&req->log, lvl, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2016-07-08 18:48:41 +02:00
|
|
|
read_json_body(struct http_request *http_req, struct jsonrpc_request *req)
|
2016-07-05 17:27:30 +02:00
|
|
|
{
|
|
|
|
char *body_string;
|
|
|
|
ssize_t body_len = 0, chunk_len;
|
|
|
|
u_int8_t chunk_buffer[BUFSIZ];
|
|
|
|
char error_buffer[1024];
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
chunk_len = http_body_read(http_req, chunk_buffer,
|
|
|
|
sizeof(chunk_buffer));
|
|
|
|
if (chunk_len == -1) {
|
|
|
|
jsonrpc_log(req, LOG_CRIT,
|
|
|
|
"Failed to read request body");
|
|
|
|
return (JSONRPC_SERVER_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chunk_len == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (body_len > SSIZE_MAX - chunk_len) {
|
|
|
|
jsonrpc_log(req, LOG_CRIT,
|
|
|
|
"Request body bigger than the platform accepts");
|
|
|
|
return (JSONRPC_SERVER_ERROR);
|
|
|
|
}
|
|
|
|
body_len += chunk_len;
|
|
|
|
|
|
|
|
kore_buf_append(&req->buf, chunk_buffer, chunk_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Grab our body data as a NUL-terminated string. */
|
2016-07-09 15:14:03 +02:00
|
|
|
body_string = kore_buf_stringify(&req->buf, NULL);
|
2016-07-05 17:27:30 +02:00
|
|
|
|
|
|
|
/* Parse the body via yajl now. */
|
|
|
|
*error_buffer = 0;
|
|
|
|
req->json = yajl_tree_parse(body_string, error_buffer,
|
|
|
|
sizeof(error_buffer));
|
|
|
|
if (req->json == NULL) {
|
|
|
|
if (strlen(error_buffer)) {
|
|
|
|
jsonrpc_log(req, LOG_ERR, "Invalid json: %s",
|
|
|
|
error_buffer);
|
|
|
|
} else {
|
|
|
|
jsonrpc_log(req, LOG_ERR, "Invalid json");
|
|
|
|
}
|
|
|
|
return (JSONRPC_PARSE_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
parse_json_body(struct jsonrpc_request *req)
|
|
|
|
{
|
|
|
|
static const char *proto_path[] = { "jsonrpc", NULL };
|
|
|
|
static const char *id_path[] = { "id", NULL };
|
|
|
|
static const char *method_path[] = { "method", NULL };
|
|
|
|
static const char *params_path[] = { "params", NULL };
|
|
|
|
|
|
|
|
/* Check protocol first. */
|
|
|
|
yajl_val proto = yajl_tree_get(req->json, proto_path, yajl_t_string);
|
|
|
|
if (proto == NULL) {
|
|
|
|
jsonrpc_log(req, LOG_ERR,
|
|
|
|
"JSON-RPC protocol MUST be indicated and \"2.0\"");
|
|
|
|
return (JSONRPC_PARSE_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *proto_string = YAJL_GET_STRING(proto);
|
|
|
|
if (proto_string == NULL) {
|
|
|
|
jsonrpc_log(req, LOG_ERR,
|
|
|
|
"JSON-RPC protocol MUST be indicated and \"2.0\"");
|
|
|
|
return (JSONRPC_PARSE_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp("2.0", proto_string) != 0) {
|
|
|
|
jsonrpc_log(req, LOG_ERR,
|
|
|
|
"JSON-RPC protocol MUST be indicated and \"2.0\"");
|
|
|
|
return (JSONRPC_PARSE_ERROR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check id. */
|
|
|
|
if ((req->id = yajl_tree_get(req->json, id_path, yajl_t_any)) != NULL) {
|
|
|
|
if (YAJL_IS_NUMBER(req->id)) {
|
|
|
|
if (!YAJL_IS_INTEGER(req->id)) {
|
|
|
|
jsonrpc_log(req, LOG_ERR,
|
|
|
|
"JSON-RPC id SHOULD NOT contain fractional"
|
|
|
|
" parts");
|
|
|
|
return (JSONRPC_PARSE_ERROR);
|
|
|
|
}
|
|
|
|
} else if (!YAJL_IS_STRING(req->id)) {
|
|
|
|
jsonrpc_log(req, LOG_ERR,
|
|
|
|
"JSON-RPC id MUST contain a String or Number");
|
|
|
|
return (JSONRPC_PARSE_ERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check method. */
|
|
|
|
if ((req->method = YAJL_GET_STRING(yajl_tree_get(req->json, method_path,
|
|
|
|
yajl_t_string))) == NULL) {
|
|
|
|
jsonrpc_log(req, LOG_ERR,
|
|
|
|
"JSON-RPC method MUST exist and be a String");
|
|
|
|
return (JSONRPC_PARSE_ERROR);
|
|
|
|
}
|
|
|
|
|
2016-07-07 14:41:10 +02:00
|
|
|
/* Check params. */
|
2016-07-05 17:27:30 +02:00
|
|
|
req->params = yajl_tree_get(req->json, params_path, yajl_t_any);
|
2016-07-07 14:41:10 +02:00
|
|
|
if (!(req->params == NULL || YAJL_IS_ARRAY(req->params)
|
|
|
|
|| YAJL_IS_OBJECT(req->params))) {
|
|
|
|
jsonrpc_log(req, LOG_ERR,
|
|
|
|
"JSON-RPC params MUST be Object or Array");
|
|
|
|
return (JSONRPC_PARSE_ERROR);
|
|
|
|
}
|
2016-07-05 17:27:30 +02:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2016-07-09 12:21:03 +02:00
|
|
|
jsonrpc_read_request(struct http_request *http_req, struct jsonrpc_request *req)
|
2016-07-05 17:27:30 +02:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
init_request(req);
|
|
|
|
req->http = http_req;
|
|
|
|
|
2016-07-08 18:48:41 +02:00
|
|
|
if ((ret = read_json_body(http_req, req)) != 0)
|
2016-07-05 17:27:30 +02:00
|
|
|
return (ret);
|
|
|
|
|
|
|
|
return parse_json_body(req);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
write_id(yajl_gen gen, yajl_val id)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
|
|
|
|
if (YAJL_GEN_KO(status = YAJL_GEN_CONST_STRING(gen, "id")))
|
|
|
|
return (status);
|
|
|
|
|
|
|
|
if (YAJL_IS_NULL(id))
|
|
|
|
return yajl_gen_null(gen);
|
|
|
|
|
|
|
|
if (YAJL_IS_NUMBER(id)) {
|
|
|
|
if (YAJL_IS_INTEGER(id))
|
|
|
|
return yajl_gen_integer(gen, YAJL_GET_INTEGER(id));
|
2016-07-06 21:06:50 +02:00
|
|
|
return yajl_gen_null(gen);
|
2016-07-05 17:27:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (YAJL_IS_STRING(id)) {
|
|
|
|
char *id_str = YAJL_GET_STRING(id);
|
|
|
|
|
|
|
|
return yajl_gen_string(gen, (unsigned char *)id_str,
|
|
|
|
strlen(id_str));
|
|
|
|
}
|
|
|
|
|
2016-07-06 21:06:50 +02:00
|
|
|
return yajl_gen_null(gen);
|
2016-07-05 17:27:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
open_response(yajl_gen genctx, yajl_val id)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
|
|
|
|
if (YAJL_GEN_KO(status = yajl_gen_map_open(genctx)))
|
|
|
|
goto failed;
|
|
|
|
if (YAJL_GEN_KO(status = YAJL_GEN_CONST_STRING(genctx, "jsonrpc")))
|
|
|
|
goto failed;
|
|
|
|
if (YAJL_GEN_KO(status = YAJL_GEN_CONST_STRING(genctx, "2.0")))
|
|
|
|
goto failed;
|
|
|
|
status = write_id(genctx, id);
|
|
|
|
failed:
|
|
|
|
return (status);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
close_response(yajl_gen genctx)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
|
|
|
|
if (YAJL_GEN_KO(status = yajl_gen_map_close(genctx)))
|
|
|
|
goto failed;
|
|
|
|
status = yajl_gen_map_close(genctx);
|
|
|
|
failed:
|
|
|
|
return (status);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
write_log(struct jsonrpc_request *req)
|
|
|
|
{
|
|
|
|
bool wrote_smth = false;
|
|
|
|
int status = 0;
|
|
|
|
|
|
|
|
for (struct jsonrpc_log *log = req->log.next; log != &req->log;
|
|
|
|
log = log->next) {
|
|
|
|
|
|
|
|
if (((1 << log->lvl) & req->log_levels) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!wrote_smth) {
|
|
|
|
if (YAJL_GEN_KO(status = YAJL_GEN_CONST_STRING(req->gen,
|
|
|
|
"data")))
|
|
|
|
goto failed;
|
|
|
|
if (YAJL_GEN_KO(status = yajl_gen_array_open(req->gen)))
|
|
|
|
goto failed;
|
|
|
|
yajl_gen_config(req->gen, yajl_gen_validate_utf8, 1);
|
|
|
|
wrote_smth = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (YAJL_GEN_KO(status = yajl_gen_array_open(req->gen)))
|
|
|
|
goto failed;
|
|
|
|
if (YAJL_GEN_KO(status = yajl_gen_integer(req->gen, log->lvl)))
|
|
|
|
goto failed;
|
|
|
|
if (YAJL_GEN_KO(status = yajl_gen_string(req->gen,
|
|
|
|
(unsigned char *)log->msg, strlen(log->msg))))
|
|
|
|
goto failed;
|
|
|
|
if (YAJL_GEN_KO(status = yajl_gen_array_close(req->gen)))
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wrote_smth) {
|
|
|
|
yajl_gen_config(req->gen, yajl_gen_validate_utf8, 0);
|
|
|
|
status = yajl_gen_array_close(req->gen);
|
|
|
|
}
|
|
|
|
failed:
|
|
|
|
return (status);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
write_error(struct jsonrpc_request *req, int code, const char *message)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
|
|
|
|
yajl_gen_config(req->gen, yajl_gen_validate_utf8, 0);
|
|
|
|
|
|
|
|
if (YAJL_GEN_KO(status = open_response(req->gen, req->id)))
|
|
|
|
goto failed;
|
|
|
|
if (YAJL_GEN_KO(status = YAJL_GEN_CONST_STRING(req->gen, "error")))
|
|
|
|
goto failed;
|
|
|
|
if (YAJL_GEN_KO(status = yajl_gen_map_open(req->gen)))
|
|
|
|
goto failed;
|
|
|
|
if (YAJL_GEN_KO(status = YAJL_GEN_CONST_STRING(req->gen, "code")))
|
|
|
|
goto failed;
|
|
|
|
if (YAJL_GEN_KO(status = yajl_gen_integer(req->gen, code)))
|
|
|
|
goto failed;
|
|
|
|
if (YAJL_GEN_KO(status = YAJL_GEN_CONST_STRING(req->gen, "message")))
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
yajl_gen_config(req->gen, yajl_gen_validate_utf8, 1);
|
|
|
|
|
|
|
|
if (YAJL_GEN_KO(status = yajl_gen_string(req->gen,
|
|
|
|
(const unsigned char *)message, strlen(message))))
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
yajl_gen_config(req->gen, yajl_gen_validate_utf8, 0);
|
|
|
|
|
|
|
|
if (YAJL_GEN_KO(status = write_log(req)))
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
status = close_response(req->gen);
|
|
|
|
failed:
|
|
|
|
return (status);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
known_msg(int code)
|
|
|
|
{
|
|
|
|
switch (code) {
|
|
|
|
case JSONRPC_PARSE_ERROR:
|
|
|
|
return (JSONRPC_PARSE_ERROR_MSG);
|
|
|
|
case JSONRPC_INVALID_REQUEST:
|
|
|
|
return (JSONRPC_INVALID_REQUEST_MSG);
|
|
|
|
case JSONRPC_METHOD_NOT_FOUND:
|
|
|
|
return (JSONRPC_METHOD_NOT_FOUND_MSG);
|
|
|
|
case JSONRPC_INVALID_PARAMS:
|
|
|
|
return (JSONRPC_INVALID_PARAMS_MSG);
|
|
|
|
case JSONRPC_INTERNAL_ERROR:
|
|
|
|
return (JSONRPC_INTERNAL_ERROR_MSG);
|
|
|
|
case JSONRPC_SERVER_ERROR:
|
|
|
|
return (JSONRPC_SERVER_ERROR_MSG);
|
|
|
|
case JSONRPC_LIMIT_REACHED:
|
|
|
|
return (JSONRPC_LIMIT_REACHED_MSG);
|
|
|
|
default:
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
jsonrpc_error(struct jsonrpc_request *req, int code, const char *msg)
|
|
|
|
{
|
|
|
|
char *msg_fallback;
|
2016-07-06 21:06:50 +02:00
|
|
|
const unsigned char *body = NULL;
|
|
|
|
size_t body_len = 0;
|
2016-07-05 17:27:30 +02:00
|
|
|
int status;
|
|
|
|
|
2016-07-06 21:06:50 +02:00
|
|
|
if (req->id == NULL)
|
|
|
|
goto succeeded;
|
|
|
|
|
2016-07-05 17:27:30 +02:00
|
|
|
if ((req->gen = yajl_gen_alloc(NULL)) == NULL) {
|
|
|
|
kore_log(LOG_ERR, "jsonrpc_error: Failed to allocate yajl gen");
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
yajl_gen_config(req->gen, yajl_gen_beautify,
|
|
|
|
req->flags & yajl_gen_beautify);
|
|
|
|
|
|
|
|
if (msg == NULL)
|
|
|
|
msg = known_msg(code);
|
|
|
|
|
|
|
|
if (msg == NULL) {
|
2016-07-09 15:14:03 +02:00
|
|
|
size_t start = req->buf.offset;
|
2016-07-05 17:27:30 +02:00
|
|
|
kore_buf_appendf(&req->buf, "%d", code);
|
|
|
|
msg_fallback = kore_buf_stringify(&req->buf, NULL) + start;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (YAJL_GEN_KO(status = write_error(req, code,
|
|
|
|
msg ? msg : msg_fallback))) {
|
|
|
|
kore_log(LOG_ERR, "jsonrpc_error: Failed to yajl gen text [%d]",
|
|
|
|
status);
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
http_response_header(req->http, "content-type", "application/json");
|
|
|
|
yajl_gen_get_buf(req->gen, &body, &body_len);
|
2016-07-06 21:06:50 +02:00
|
|
|
succeeded:
|
2016-07-05 17:27:30 +02:00
|
|
|
http_response(req->http, 200, body, body_len);
|
2016-07-06 21:06:50 +02:00
|
|
|
if (req->gen != NULL)
|
|
|
|
yajl_gen_clear(req->gen);
|
2016-07-12 13:03:46 +02:00
|
|
|
jsonrpc_destroy_request(req);
|
2016-07-05 17:27:30 +02:00
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
failed:
|
|
|
|
http_response(req->http, 500, NULL, 0);
|
2016-07-12 13:03:46 +02:00
|
|
|
jsonrpc_destroy_request(req);
|
2016-07-05 17:27:30 +02:00
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
jsonrpc_result(struct jsonrpc_request *req,
|
|
|
|
int (*write_result)(struct jsonrpc_request *, void *), void *ctx)
|
|
|
|
{
|
2016-07-06 21:06:50 +02:00
|
|
|
const unsigned char *body = NULL;
|
|
|
|
size_t body_len = 0;
|
|
|
|
|
|
|
|
if (req->id == NULL)
|
|
|
|
goto succeeded;
|
2016-07-05 17:27:30 +02:00
|
|
|
|
|
|
|
if ((req->gen = yajl_gen_alloc(NULL)) == NULL) {
|
|
|
|
kore_log(LOG_ERR, "jsonrpc_result: Failed to allocate yajl gen");
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
yajl_gen_config(req->gen, yajl_gen_beautify,
|
|
|
|
req->flags & yajl_gen_beautify);
|
|
|
|
|
|
|
|
yajl_gen_config(req->gen, yajl_gen_validate_utf8, 0);
|
|
|
|
|
|
|
|
if (YAJL_GEN_KO(open_response(req->gen, req->id)))
|
|
|
|
goto failed;
|
|
|
|
if (YAJL_GEN_KO(YAJL_GEN_CONST_STRING(req->gen, "result")))
|
|
|
|
goto failed;
|
|
|
|
if (YAJL_GEN_KO(write_result(req, ctx)))
|
|
|
|
goto failed;
|
|
|
|
if (YAJL_GEN_KO(yajl_gen_map_close(req->gen)))
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
http_response_header(req->http, "content-type", "application/json");
|
|
|
|
yajl_gen_get_buf(req->gen, &body, &body_len);
|
2016-07-06 21:06:50 +02:00
|
|
|
succeeded:
|
2016-07-05 17:27:30 +02:00
|
|
|
http_response(req->http, 200, body, body_len);
|
2016-07-06 21:06:50 +02:00
|
|
|
if (req->gen != NULL)
|
|
|
|
yajl_gen_clear(req->gen);
|
2016-07-12 13:03:46 +02:00
|
|
|
jsonrpc_destroy_request(req);
|
2016-07-05 17:27:30 +02:00
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
failed:
|
|
|
|
http_response(req->http, 500, NULL, 0);
|
2016-07-12 13:03:46 +02:00
|
|
|
jsonrpc_destroy_request(req);
|
2016-07-05 17:27:30 +02:00
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
}
|