/******************************************************************************
 * Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
 * iSulad licensed under the Mulan PSL v1.
 * You can use this software according to the terms and conditions of the Mulan PSL v1.
 * You may obtain a copy of Mulan PSL v1 at:
 *     http://license.coscl.org.cn/MulanPSL
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v1 for more details.
 * Author: lifeng
 * Create: 2018-11-08
 * Description: provide container restful functions
 ******************************************************************************/
#include <unistd.h>
#include "error.h"

#include "log.h"
#include "isula_connect.h"
#include "container.rest.h"
#include "pack_config.h"
#include "rest_common.h"
#include "rest_containers_client.h"

/* create request to rest */
static int create_request_to_rest(const struct isula_create_request *lc_request, char **body, size_t *body_len)
{
    container_create_request *crequest = NULL;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;
    int ret = 0;

    crequest = util_common_calloc_s(sizeof(container_create_request));
    if (crequest == NULL) {
        ERROR("Out of memory");
        ret = -1;
        goto out;
    }

    ret = generate_hostconfig(lc_request->hostconfig, &crequest->hostconfig);
    if (ret != 0) {
        ERROR("Failed to pack host config");
        ret = EINVALIDARGS;
        goto out;
    }

    ret = generate_container_config(lc_request->config, &crequest->customconfig);
    if (ret != 0) {
        ERROR("Failed to pack custom config");
        ret = EINVALIDARGS;
        goto out;
    }

    if (lc_request->name != NULL) {
        crequest->id = util_strdup_s(lc_request->name);
    }
    if (lc_request->image != NULL) {
        crequest->image = util_strdup_s(lc_request->image);
    }
    if (lc_request->rootfs != NULL) {
        crequest->rootfs = util_strdup_s(lc_request->rootfs);
    }
    if (lc_request->runtime != NULL) {
        crequest->runtime = util_strdup_s(lc_request->runtime);
    }

    *body = container_create_request_generate_json(crequest, &ctx, &err);
    if (*body == NULL) {
        ERROR("Failed to generate create request json:%s", err);
        ret = -1;
        goto out;
    }
    *body_len = strlen(*body) + 1;
out:
    free(err);
    free_container_create_request(crequest);
    return ret;
}

/* start request to rest */
static int start_request_to_rest(const struct isula_start_request *ls_request, char **body, size_t *body_len)
{
    container_start_request *crequest = NULL;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;
    int ret = 0;

    crequest = util_common_calloc_s(sizeof(container_start_request));
    if (crequest == NULL) {
        ERROR("Out of memory");
        return -1;
    }

    if (ls_request->name != NULL) {
        crequest->id = util_strdup_s(ls_request->name);
    }
    if (ls_request->stdout != NULL) {
        crequest->stdout = util_strdup_s(ls_request->stdout);
    }
    if (ls_request->stdin != NULL) {
        crequest->stdin = util_strdup_s(ls_request->stdin);
    }
    if (ls_request->stderr != NULL) {
        crequest->stderr = util_strdup_s(ls_request->stderr);
    }
    crequest->attach_stdin = ls_request->attach_stdin;
    crequest->attach_stdout = ls_request->attach_stdout;
    crequest->attach_stderr = ls_request->attach_stderr;

    *body = container_start_request_generate_json(crequest, &ctx, &err);
    if (*body == NULL) {
        ERROR("Failed to generate start request json:%s", err);
        ret = -1;
        goto out;
    }
    *body_len = strlen(*body) + 1;
out:
    free(err);
    free_container_start_request(crequest);
    return ret;
}

/* list request to rest */
static int list_request_to_rest(const struct isula_list_request *ll_request, char **body, size_t *body_len)
{
    container_list_request *crequest = NULL;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;
    int ret = 0;
    size_t i, len;

    crequest = util_common_calloc_s(sizeof(container_list_request));
    if (crequest == NULL) {
        ERROR("Out of memory");
        return -1;
    }

    crequest->all = ll_request->all;

    if (ll_request->filters == NULL || ll_request->filters->len == 0) {
        goto pack_json;
    }

    crequest->filters = util_common_calloc_s(sizeof(defs_filters));
    if (crequest->filters == NULL) {
        ERROR("Out of memory");
        ret = -1;
        goto out;
    }

    len = ll_request->filters->len;
    if (len > SIZE_MAX / sizeof(char *)) {
        ERROR("Too many filters");
        ret = -1;
        goto out;
    }
    crequest->filters->keys = (char **)util_common_calloc_s(len * sizeof(char *));
    if (crequest->filters->keys == NULL) {
        ERROR("Out of memory");
        ret = -1;
        goto out;
    }
    crequest->filters->values = (json_map_string_bool **)util_common_calloc_s(len * sizeof(json_map_string_bool *));
    if (crequest->filters->values == NULL) {
        ERROR("Out of memory");
        free(crequest->filters->keys);
        crequest->filters->keys = NULL;
        ret = -1;
        goto out;
    }

    for (i = 0; i < ll_request->filters->len; i++) {
        crequest->filters->values[crequest->filters->len] = util_common_calloc_s(sizeof(json_map_string_bool));
        if (crequest->filters->values[crequest->filters->len] == NULL) {
            ERROR("Out of memory");
            ret = -1;
            goto out;
        }
        if (append_json_map_string_bool(crequest->filters->values[crequest->filters->len],
                                        ll_request->filters->values[i], true)) {
            free(crequest->filters->values[crequest->filters->len]);
            crequest->filters->values[crequest->filters->len] = NULL;
            ERROR("Append failed");
            ret = -1;
            goto out;
        }
        crequest->filters->keys[crequest->filters->len] = util_strdup_s(ll_request->filters->keys[i]);
        crequest->filters->len++;
    }

pack_json:
    *body = container_list_request_generate_json(crequest, &ctx, &err);
    if (*body == NULL) {
        ERROR("Failed to generate list request json:%s", err);
        ret = -1;
        goto out;
    }
    *body_len = strlen(*body) + 1;
out:
    free(err);
    free_container_list_request(crequest);
    return ret;
}

/* attach request to rest */
static int attach_request_to_rest(const struct isula_attach_request *la_request, char **body, size_t *body_len)
{
    container_attach_request *crequest = NULL;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;
    int ret = 0;

    crequest = util_common_calloc_s(sizeof(container_attach_request));
    if (crequest == NULL) {
        ERROR("Out of memory");
        return -1;
    }

    if (la_request->name != NULL) {
        crequest->container_id = util_strdup_s(la_request->name);
    }
    if (la_request->stdout != NULL) {
        crequest->stdout = util_strdup_s(la_request->stdout);
    }
    if (la_request->stdin != NULL) {
        crequest->stdin = util_strdup_s(la_request->stdin);
    }
    if (la_request->stderr != NULL) {
        crequest->stderr = util_strdup_s(la_request->stderr);
    }
    *body = container_attach_request_generate_json(crequest, &ctx, &err);
    if (*body == NULL) {
        ERROR("Failed to generate attach request json:%s", err);
        ret = -1;
        goto out;
    }
    *body_len = strlen(*body) + 1;
out:
    free(err);
    free_container_attach_request(crequest);
    return ret;
}

/* resume request to rest */
static int resume_request_to_rest(const struct isula_resume_request *lr_request, char **body, size_t *body_len)
{
    container_resume_request *crequest = NULL;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;
    int ret = 0;

    crequest = util_common_calloc_s(sizeof(container_resume_request));
    if (crequest == NULL) {
        ERROR("Out of memory");
        return -1;
    }

    if (lr_request->name != NULL) {
        crequest->id = util_strdup_s(lr_request->name);
    }
    *body = container_resume_request_generate_json(crequest, &ctx, &err);
    if (*body == NULL) {
        ERROR("Failed to generate resume request json:%s", err);
        ret = -1;
        goto out;
    }
    *body_len = strlen(*body) + 1;
out:
    free(err);
    free_container_resume_request(crequest);
    return ret;
}

/* wait request to rest */
static int wait_request_to_rest(const struct isula_wait_request *lw_request, char **body, size_t *body_len)
{
    container_wait_request *crequest = NULL;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;
    int ret = 0;

    crequest = util_common_calloc_s(sizeof(container_wait_request));
    if (crequest == NULL) {
        ERROR("Out of memory");
        return -1;
    }

    if (lw_request->id != NULL) {
        crequest->id = util_strdup_s(lw_request->id);
    }
    crequest->condition = lw_request->condition;

    *body = container_wait_request_generate_json(crequest, &ctx, &err);
    if (*body == NULL) {
        ERROR("Failed to generate wait request json:%s", err);
        ret = -1;
        goto out;
    }
    *body_len = strlen(*body) + 1;
out:
    free(err);
    free_container_wait_request(crequest);
    return ret;
}

/* unpack create response */
static int unpack_create_response(const struct parsed_http_message *message, void *arg)
{
    struct isula_create_response *response = arg;
    container_create_response *cresponse = NULL;
    parser_error err = NULL;
    int ret = 0;

    ret = check_status_code(message->status_code);
    if (ret != 0) {
        goto out;
    }

    cresponse = container_create_response_parse_data(message->body, NULL, &err);
    if (cresponse == NULL) {
        ERROR("Invalid create response:%s", err);
        ret = -1;
        goto out;
    }
    response->server_errono = cresponse->cc;
    if (cresponse->errmsg != NULL) {
        response->errmsg = util_strdup_s(cresponse->errmsg);
    }
    if (cresponse->id != NULL) {
        response->id = util_strdup_s(cresponse->id);
    }
    ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1;
    if (message->status_code == RESTFUL_RES_SERVERR) {
        ret = -1;
    }

out:
    free(err);
    free_container_create_response(cresponse);
    return ret;
}

/* unpack start response */
static int unpack_start_response(const struct parsed_http_message *message, void *arg)
{
    struct isula_start_response *start_response = arg;
    container_start_response *cresponse = NULL;
    parser_error err = NULL;
    int ret = 0;

    ret = check_status_code(message->status_code);
    if (ret != 0) {
        goto out;
    }

    cresponse = container_start_response_parse_data(message->body, NULL, &err);
    if (cresponse == NULL) {
        ERROR("Invalid start response:%s", err);
        ret = -1;
        goto out;
    }
    start_response->server_errono = cresponse->cc;
    if (cresponse->errmsg != NULL) {
        start_response->errmsg = util_strdup_s(cresponse->errmsg);
    }
    ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1;
    if (message->status_code == RESTFUL_RES_SERVERR) {
        ret = -1;
    }

out:
    free(err);
    free_container_start_response(cresponse);
    return ret;
}

static int unpack_container_info_for_list_response(container_list_response *cresponse,
                                                   struct isula_list_response *response)
{
    size_t num = 0;
    size_t i = 0;
    struct isula_container_summary_info **summary_info = NULL;

    if (cresponse == NULL || response == NULL) {
        return -1;
    }

    num = cresponse->containers_len;
    if (num == 0) {
        return 0;
    }
    if (num > SIZE_MAX / sizeof(struct isula_container_summary_info *)) {
        ERROR("Too many container summaries");
        return -1;
    }
    summary_info = (struct isula_container_summary_info **)util_common_calloc_s(
                       sizeof(struct isula_container_summary_info *) * num);
    if (summary_info == NULL) {
        ERROR("out of memory");
        return -1;
    }
    response->container_num = num;
    response->container_summary = summary_info;
    for (i = 0; i < num; i++) {
        summary_info[i] =
            (struct isula_container_summary_info *)util_common_calloc_s(sizeof(struct isula_container_summary_info));
        if (summary_info[i] == NULL) {
            ERROR("Out of memory");
            return -1;
        }
        summary_info[i]->id = cresponse->containers[i]->id ? util_strdup_s(cresponse->containers[i]->id)
                              : util_strdup_s("-");
        summary_info[i]->name = cresponse->containers[i]->name ? util_strdup_s(cresponse->containers[i]->name)
                                : util_strdup_s("-");
        summary_info[i]->runtime = cresponse->containers[i]->runtime ? util_strdup_s(cresponse->containers[i]->runtime)
                                   : util_strdup_s("-");
        summary_info[i]->has_pid = cresponse->containers[i]->pid != 0;
        summary_info[i]->pid = cresponse->containers[i]->pid;
        summary_info[i]->status = cresponse->containers[i]->status;
        summary_info[i]->image = cresponse->containers[i]->image ? util_strdup_s(cresponse->containers[i]->image)
                                 : util_strdup_s("-");
        summary_info[i]->command = cresponse->containers[i]->command ? util_strdup_s(cresponse->containers[i]->command)
                                   : util_strdup_s("-");
        summary_info[i]->startat = cresponse->containers[i]->startat ? util_strdup_s(cresponse->containers[i]->startat)
                                   : util_strdup_s("-");
        summary_info[i]->finishat = cresponse->containers[i]->finishat ?
                                    util_strdup_s(cresponse->containers[i]->finishat) : util_strdup_s("-");
        summary_info[i]->exit_code = cresponse->containers[i]->exit_code;
        summary_info[i]->restart_count = (unsigned int)cresponse->containers[i]->restartcount;
    }

    return 0;
}
/* unpack list response */
static int unpack_list_response(const struct parsed_http_message *message, void *arg)
{
    struct isula_list_response *response = arg;
    container_list_response *cresponse = NULL;
    parser_error err = NULL;
    int ret = 0;

    ret = check_status_code(message->status_code);
    if (ret != 0) {
        goto out;
    }

    cresponse = container_list_response_parse_data(message->body, NULL, &err);
    if (cresponse == NULL) {
        ERROR("Invalid list response:%s", err);
        ret = -1;
        goto out;
    }
    response->server_errono = cresponse->cc;
    if (cresponse->errmsg != NULL) {
        response->errmsg = util_strdup_s(cresponse->errmsg);
    }
    ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1;
    if (message->status_code == RESTFUL_RES_SERVERR) {
        ret = -1;
    }
    if (unpack_container_info_for_list_response(cresponse, response)) {
        ret = -1;
        goto out;
    }

out:
    free(err);
    free_container_list_response(cresponse);
    return ret;
}

/* unpack attach response */
static int unpack_attach_response(const struct parsed_http_message *message, void *arg)
{
    struct isula_attach_response *attach_response = arg;
    container_attach_response *cresponse = NULL;
    parser_error err = NULL;
    int ret = 0;

    ret = check_status_code(message->status_code);
    if (ret != 0) {
        goto out;
    }

    cresponse = container_attach_response_parse_data(message->body, NULL, &err);
    if (cresponse == NULL) {
        ERROR("Invalid attach response:%s", err);
        ret = -1;
        goto out;
    }
    attach_response->server_errono = cresponse->cc;
    if (cresponse->errmsg != NULL) {
        attach_response->errmsg = util_strdup_s(cresponse->errmsg);
    }
    ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1;
    if (message->status_code == RESTFUL_RES_SERVERR) {
        ret = -1;
    }

out:
    free(err);
    free_container_attach_response(cresponse);
    return ret;
}

/* unpack resume response */
static int unpack_resume_response(const struct parsed_http_message *message, void *arg)
{
    struct isula_resume_response *resume_response = arg;
    container_resume_response *cresponse = NULL;
    parser_error err = NULL;
    int ret = 0;

    ret = check_status_code(message->status_code);
    if (ret != 0) {
        goto out;
    }

    cresponse = container_resume_response_parse_data(message->body, NULL, &err);
    if (cresponse == NULL) {
        ERROR("Invalid resume response:%s", err);
        ret = -1;
        goto out;
    }
    resume_response->server_errono = cresponse->cc;
    if (cresponse->errmsg != NULL) {
        resume_response->errmsg = util_strdup_s(cresponse->errmsg);
    }
    ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1;
    if (message->status_code == RESTFUL_RES_SERVERR) {
        ret = -1;
    }

out:
    free(err);
    free_container_resume_response(cresponse);
    return ret;
}

/* unpack wait response */
static int unpack_wait_response(const struct parsed_http_message *message, void *arg)
{
    struct isula_wait_response *response = arg;
    container_wait_response *cresponse = NULL;
    parser_error err = NULL;
    int ret = 0;

    ret = check_status_code(message->status_code);
    if (ret != 0) {
        goto out;
    }

    cresponse = container_wait_response_parse_data(message->body, NULL, &err);
    if (cresponse == NULL) {
        ERROR("Invalid create response:%s", err);
        ret = -1;
        goto out;
    }
    response->server_errono = cresponse->cc;
    response->exit_code = (int)cresponse->exit_code;
    if (cresponse->errmsg != NULL) {
        response->errmsg = util_strdup_s(cresponse->errmsg);
    }
    ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1;
    if (message->status_code == RESTFUL_RES_SERVERR) {
        ret = -1;
    }

out:
    free_container_wait_response(cresponse);
    free(err);
    return ret;
}

/* rest container create */
static int rest_container_create(const struct isula_create_request *lc_request,
                                 struct isula_create_response *lc_response, void *arg)
{
    char *body = NULL;
    int ret = 0;
    size_t len = 0;
    client_connect_config_t *connect_config = (client_connect_config_t *)arg;
    const char *socketname = (const char *)(connect_config->socket);
    Buffer *c_output = NULL;

    ret = create_request_to_rest(lc_request, &body, &len);
    if (ret != 0) {
        lc_response->cc = ISULAD_ERR_INPUT;
        goto out;
    }
    ret = rest_send_requst(socketname, RestHttpHead ContainerServiceCreate, body, len, &c_output);
    if (ret != 0) {
        lc_response->errmsg = util_strdup_s(errno_to_error_message(ISULAD_ERR_CONNECT));
        lc_response->cc = ISULAD_ERR_EXEC;
        goto out;
    }
    ret = get_response(c_output, unpack_create_response, (void *)lc_response);
    if (ret != 0) {
        goto out;
    }
out:
    if (c_output != NULL) {
        buffer_free(c_output);
    }
    put_body(body);
    return ret;
}

/* rest container start */
static int rest_container_start(const struct isula_start_request *ls_request, struct isula_start_response *ls_response,
                                void *arg)
{
    char *body = NULL;
    int ret = 0;
    size_t len = 0;
    client_connect_config_t *connect_config = (client_connect_config_t *)arg;
    const char *socketname = (const char *)(connect_config->socket);
    Buffer *s_output = NULL;

    ret = start_request_to_rest(ls_request, &body, &len);
    if (ret != 0) {
        goto out;
    }
    ret = rest_send_requst(socketname, RestHttpHead ContainerServiceStart, body, len, &s_output);
    if (ret != 0) {
        ls_response->errmsg = util_strdup_s(errno_to_error_message(ISULAD_ERR_CONNECT));
        ls_response->cc = ISULAD_ERR_EXEC;
        ls_response->server_errono = ISULAD_ERR_EXEC;
        goto out;
    }
    ret = get_response(s_output, unpack_start_response, (void *)ls_response);
    if (ret != 0) {
        goto out;
    }
out:
    if (s_output != NULL) {
        buffer_free(s_output);
    }
    put_body(body);
    return ret;
}

/* rest container attach */
static int rest_container_attach(const struct isula_attach_request *la_request,
                                 struct isula_attach_response *la_response, void *arg)
{
    char *body = NULL;
    int ret = 0;
    size_t len = 0;
    client_connect_config_t *connect_config = (client_connect_config_t *)arg;
    const char *socketname = (const char *)(connect_config->socket);
    Buffer *a_output = NULL;

    ret = attach_request_to_rest(la_request, &body, &len);
    if (ret != 0) {
        goto out;
    }
    ret = rest_send_requst(socketname, RestHttpHead ContainerServiceAttach, body, len, &a_output);
    if (ret != 0) {
        la_response->errmsg = util_strdup_s(errno_to_error_message(ISULAD_ERR_CONNECT));
        la_response->cc = ISULAD_ERR_EXEC;
        goto out;
    }
    ret = get_response(a_output, unpack_attach_response, (void *)la_response);
    if (ret != 0) {
        goto out;
    }
out:
    if (a_output != NULL) {
        buffer_free(a_output);
    }
    put_body(body);
    return ret;
}

/* rest container list */
static int rest_container_list(const struct isula_list_request *ll_request,
                               struct isula_list_response *ll_response, void *arg)
{
    char *body = NULL;
    int ret = 0;
    size_t len = 0;
    client_connect_config_t *connect_config = (client_connect_config_t *)arg;
    const char *socketname = (const char *)(connect_config->socket);
    Buffer *l_output = NULL;

    ret = list_request_to_rest(ll_request, &body, &len);
    if (ret != 0) {
        goto out;
    }
    ret = rest_send_requst(socketname, RestHttpHead ContainerServiceList, body, len, &l_output);
    if (ret != 0) {
        ll_response->errmsg = util_strdup_s(errno_to_error_message(ISULAD_ERR_CONNECT));
        ll_response->cc = ISULAD_ERR_EXEC;
        goto out;
    }
    ret = get_response(l_output, unpack_list_response, (void *)ll_response);
    if (ret != 0) {
        goto out;
    }
out:
    if (l_output != NULL) {
        buffer_free(l_output);
    }
    put_body(body);
    return ret;
}

/* rest container resume */
static int rest_container_resume(const struct isula_resume_request *lr_request,
                                 struct isula_resume_response *lr_response, void *arg)
{
    char *body = NULL;
    int ret = 0;
    size_t len = 0;
    client_connect_config_t *connect_config = (client_connect_config_t *)arg;
    const char *socketname = (const char *)(connect_config->socket);
    Buffer *r_output = NULL;

    ret = resume_request_to_rest(lr_request, &body, &len);
    if (ret != 0) {
        goto out;
    }
    ret = rest_send_requst(socketname, RestHttpHead ContainerServiceResume, body, len, &r_output);
    if (ret != 0) {
        lr_response->errmsg = util_strdup_s(errno_to_error_message(ISULAD_ERR_CONNECT));
        lr_response->cc = ISULAD_ERR_EXEC;
        goto out;
    }
    ret = get_response(r_output, unpack_resume_response, (void *)lr_response);
    if (ret != 0) {
        goto out;
    }
out:
    if (r_output != NULL) {
        buffer_free(r_output);
    }
    put_body(body);
    return ret;
}

/* rest container wait */
static int rest_container_wait(const struct isula_wait_request *lw_request,
                               struct isula_wait_response *lw_response, void *arg)
{
    char *body = NULL;
    int ret = 0;
    size_t len = 0;
    client_connect_config_t *connect_config = (client_connect_config_t *)arg;
    const char *socketname = (const char *)(connect_config->socket);
    Buffer *w_output = NULL;

    ret = wait_request_to_rest(lw_request, &body, &len);
    if (ret != 0) {
        goto out;
    }
    ret = rest_send_requst(socketname, RestHttpHead ContainerServiceWait, body, len, &w_output);
    if (ret != 0) {
        lw_response->errmsg = util_strdup_s(errno_to_error_message(ISULAD_ERR_CONNECT));
        lw_response->cc = ISULAD_ERR_EXEC;
        goto out;
    }
    ret = get_response(w_output, unpack_wait_response, (void *)lw_response);
    if (ret != 0) {
        goto out;
    }
out:
    if (w_output != NULL) {
        buffer_free(w_output);
    }
    put_body(body);
    return ret;
}

/* stop request to rest */
static int stop_request_to_rest(const struct isula_stop_request *ls_request, char **body, size_t *body_len)
{
    container_stop_request *crequest = NULL;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;
    int ret = 0;

    crequest = util_common_calloc_s(sizeof(container_stop_request));
    if (crequest == NULL) {
        ERROR("Out of memory");
        ret = -1;
        goto out;
    }

    if (ls_request->name != NULL) {
        crequest->id = util_strdup_s(ls_request->name);
    }
    crequest->force = ls_request->force;
    crequest->timeout = ls_request->timeout;

    *body = container_stop_request_generate_json(crequest, &ctx, &err);
    if (*body == NULL) {
        ERROR("Failed to generate stop request json:%s", err);
        ret = -1;
        goto out;
    }
    *body_len = strlen(*body) + 1;
out:
    free(err);
    free_container_stop_request(crequest);
    return ret;
}

/* unpack stop response */
static int unpack_stop_response(const struct parsed_http_message *message, void *arg)
{
    struct isula_stop_response *stop_response = arg;
    container_stop_response *cresponse = NULL;
    parser_error err = NULL;
    int ret = 0;

    ret = check_status_code(message->status_code);
    if (ret != 0) {
        goto out;
    }

    cresponse = container_stop_response_parse_data(message->body, NULL, &err);
    if (cresponse == NULL) {
        ERROR("Invalid stop response:%s", err);
        ret = -1;
        goto out;
    }
    stop_response->server_errono = cresponse->cc;
    if (cresponse->errmsg != NULL) {
        stop_response->errmsg = util_strdup_s(cresponse->errmsg);
    }
    ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1;
    if (message->status_code == RESTFUL_RES_SERVERR) {
        ret = -1;
    }

out:
    free(err);
    free_container_stop_response(cresponse);
    return ret;
}

/* rest container stop */
static int rest_container_stop(const struct isula_stop_request *ls_request,
                               struct isula_stop_response *ls_response, void *arg)
{
    char *body = NULL;
    int ret = 0;
    size_t len = 0;
    client_connect_config_t *connect_config = (client_connect_config_t *)arg;
    const char *socketname = (const char *)(connect_config->socket);
    Buffer *output = NULL;

    ret = stop_request_to_rest(ls_request, &body, &len);
    if (ret != 0) {
        goto out;
    }
    ret = rest_send_requst(socketname, RestHttpHead ContainerServiceStop, body, len, &output);
    if (ret != 0) {
        ls_response->errmsg = util_strdup_s(errno_to_error_message(ISULAD_ERR_CONNECT));
        ls_response->cc = ISULAD_ERR_EXEC;
        goto out;
    }
    ret = get_response(output, unpack_stop_response, (void *)ls_response);
    if (ret != 0) {
        goto out;
    }
out:
    if (output != NULL) {
        buffer_free(output);
    }
    put_body(body);
    return ret;
}

/* restart request to rest */
static int restart_request_to_rest(const struct isula_restart_request *lr_request, char **body, size_t *body_len)
{
    container_restart_request *creq = NULL;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;
    int ret = 0;

    creq = util_common_calloc_s(sizeof(container_restart_request));
    if (creq == NULL) {
        ERROR("Out of memory");
        ret = -1;
        goto out;
    }

    if (lr_request->name != NULL) {
        creq->id = util_strdup_s(lr_request->name);
    }
    creq->timeout = (int32_t)lr_request->timeout;

    *body = container_restart_request_generate_json(creq, &ctx, &err);
    if (*body == NULL) {
        ERROR("Failed to generate restart request json: %s", err);
        ret = -1;
        goto out;
    }
    *body_len = strlen(*body) + 1;
out:
    free(err);
    free_container_restart_request(creq);
    return ret;
}

/* unpack restart response */
static int unpack_restart_response(const struct parsed_http_message *message, void *arg)
{
    struct isula_restart_response *response = arg;
    container_restart_response *cres = NULL;
    parser_error err = NULL;
    int ret = 0;

    ret = check_status_code(message->status_code);
    if (ret != 0) {
        goto out;
    }

    cres = container_restart_response_parse_data(message->body, NULL, &err);
    if (cres == NULL) {
        ERROR("Invalid restart response: %s", err);
        ret = -1;
        goto out;
    }
    response->server_errono = cres->cc;
    if (cres->errmsg != NULL) {
        response->errmsg = util_strdup_s(cres->errmsg);
    }
    ret = (cres->cc == ISULAD_SUCCESS) ? 0 : -1;
    if (message->status_code == RESTFUL_RES_SERVERR) {
        ret = -1;
    }

out:
    free(err);
    free_container_restart_response(cres);
    return ret;
}

/* rest container restart */
static int rest_container_restart(const struct isula_restart_request *lr_request,
                                  struct isula_restart_response *lr_response, void *arg)
{
    char *body = NULL;
    int ret = 0;
    size_t len = 0;
    client_connect_config_t *connect_config = (client_connect_config_t *)arg;
    const char *socketname = (const char *)(connect_config->socket);
    Buffer *output = NULL;

    ret = restart_request_to_rest(lr_request, &body, &len);
    if (ret != 0) {
        goto out;
    }
    ret = rest_send_requst(socketname, RestHttpHead ContainerServiceRestart, body, len, &output);
    if (ret != 0) {
        lr_response->errmsg = util_strdup_s(errno_to_error_message(ISULAD_ERR_CONNECT));
        lr_response->cc = ISULAD_ERR_EXEC;
        goto out;
    }
    ret = get_response(output, unpack_restart_response, (void *)lr_response);

out:
    if (output != NULL) {
        buffer_free(output);
    }
    put_body(body);
    return ret;
}

/* update request to rest */
static int update_request_to_rest(const struct isula_update_request *lu_request, char **body, size_t *body_len)
{
    container_update_request *crequest = NULL;
    isula_host_config_t srcconfig;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;
    char *srcconfigjson = NULL;
    int ret = 0;

    (void)memset(&srcconfig, 0, sizeof(srcconfig));

    crequest = util_common_calloc_s(sizeof(container_update_request));
    if (crequest == NULL) {
        ERROR("Out of memory");
        ret = -1;
        goto out;
    }

    if (lu_request->updateconfig != NULL) {
        srcconfig.restart_policy = lu_request->updateconfig->restart_policy;
        srcconfig.cr = lu_request->updateconfig->cr;
    }
    ret = generate_hostconfig(&srcconfig, &srcconfigjson);
    if (ret != 0) {
        ERROR("Failed to generate hostconfig json");
        ret = -1;
        goto out;
    }
    crequest->host_config = srcconfigjson;

    if (lu_request->name != NULL) {
        crequest->name = util_strdup_s(lu_request->name);
    }

    *body = container_update_request_generate_json(crequest, &ctx, &err);
    if (*body == NULL) {
        ERROR("Failed to generate update request json:%s", err);
        ret = -1;
        goto out;
    }
    *body_len = strlen(*body) + 1;
out:
    free(err);
    free_container_update_request(crequest);
    return ret;
}

/* unpack update response */
static int unpack_update_response(const struct parsed_http_message *message, void *arg)
{
    struct isula_update_response *update_response = arg;
    container_update_response *cresponse = NULL;
    parser_error err = NULL;
    int ret = 0;

    ret = check_status_code(message->status_code);
    if (ret != 0) {
        goto out;
    }

    cresponse = container_update_response_parse_data(message->body, NULL, &err);
    if (cresponse == NULL) {
        ERROR("Invalid update response:%s", err);
        ret = -1;
        goto out;
    }
    update_response->server_errono = cresponse->cc;
    if (cresponse->errmsg != NULL) {
        update_response->errmsg = util_strdup_s(cresponse->errmsg);
    }
    ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1;
    if (message->status_code == RESTFUL_RES_SERVERR) {
        ret = -1;
    }

out:
    free(err);
    free_container_update_response(cresponse);
    return ret;
}

/* rest container update */
static int rest_container_update(const struct isula_update_request *lu_request,
                                 struct isula_update_response *lu_response, void *arg)
{
    char *body = NULL;
    int ret = 0;
    size_t len = 0;
    client_connect_config_t *connect_config = (client_connect_config_t *)arg;
    const char *socketname = (const char *)(connect_config->socket);
    Buffer *output = NULL;

    ret = update_request_to_rest(lu_request, &body, &len);
    if (ret != 0) {
        goto out;
    }
    ret = rest_send_requst(socketname, RestHttpHead ContainerServiceUpdate, body, len, &output);
    if (ret != 0) {
        lu_response->errmsg = util_strdup_s(errno_to_error_message(ISULAD_ERR_CONNECT));
        lu_response->cc = ISULAD_ERR_EXEC;
        goto out;
    }
    ret = get_response(output, unpack_update_response, (void *)lu_response);
    if (ret != 0) {
        goto out;
    }
out:
    if (output != NULL) {
        buffer_free(output);
    }
    put_body(body);
    return ret;
}

/* version request to rest */
static int version_request_to_rest(const struct isula_version_request *lv_request, char **body, size_t *body_len)
{
    container_version_request *crequest = NULL;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;
    int ret = 0;

    crequest = util_common_calloc_s(sizeof(container_version_request));
    if (crequest == NULL) {
        ERROR("Out of memory");
        ret = -1;
        goto out;
    }

    *body = container_version_request_generate_json(crequest, &ctx, &err);
    if (*body == NULL) {
        ERROR("Failed to generate version request json:%s", err);
        ret = -1;
        goto out;
    }
    *body_len = strlen(*body) + 1;
out:
    free(err);
    free_container_version_request(crequest);
    return ret;
}

/* unpack version response */
static int unpack_version_response(const struct parsed_http_message *message, void *arg)
{
    struct isula_version_response *version_response = arg;
    container_version_response *cresponse = NULL;
    parser_error err = NULL;
    int ret = 0;

    ret = check_status_code(message->status_code);
    if (ret != 0) {
        goto out;
    }

    cresponse = container_version_response_parse_data(message->body, NULL, &err);
    if (cresponse == NULL) {
        ERROR("Invalid version response:%s", err);
        ret = -1;
        goto out;
    }
    version_response->server_errono = cresponse->cc;
    if (cresponse->version != NULL) {
        version_response->version = util_strdup_s(cresponse->version);
    }
    if (cresponse->git_commit != NULL) {
        version_response->git_commit = util_strdup_s(cresponse->git_commit);
    }
    if (cresponse->build_time != NULL) {
        version_response->build_time = util_strdup_s(cresponse->build_time);
    }
    if (cresponse->root_path != NULL) {
        version_response->root_path = util_strdup_s(cresponse->root_path);
    }
    if (cresponse->errmsg != NULL) {
        version_response->errmsg = util_strdup_s(cresponse->errmsg);
    }
    ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1;
    if (message->status_code == RESTFUL_RES_SERVERR) {
        ret = -1;
    }

out:
    free(err);
    free_container_version_response(cresponse);
    return ret;
}

/* rest container version */
static int rest_container_version(const struct isula_version_request *lv_request,
                                  struct isula_version_response *lv_response, void *arg)
{
    char *body = NULL;
    int ret = 0;
    size_t len = 0;
    client_connect_config_t *connect_config = (client_connect_config_t *)arg;
    const char *socketname = (const char *)(connect_config->socket);
    Buffer *output = NULL;

    ret = version_request_to_rest(lv_request, &body, &len);
    if (ret != 0) {
        goto out;
    }
    ret = rest_send_requst(socketname, RestHttpHead ContainerServiceVersion, body, len, &output);
    if (ret != 0) {
        lv_response->errmsg = util_strdup_s(errno_to_error_message(ISULAD_ERR_CONNECT));
        lv_response->cc = ISULAD_ERR_EXEC;
        goto out;
    }
    ret = get_response(output, unpack_version_response, (void *)lv_response);
    if (ret != 0) {
        goto out;
    }
out:
    if (output != NULL) {
        buffer_free(output);
    }
    put_body(body);
    return ret;
}

/* pause request to rest */
static int pause_request_to_rest(const struct isula_pause_request *lp_request, char **body, size_t *body_len)
{
    container_pause_request *crequest = NULL;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;
    int ret = 0;

    crequest = util_common_calloc_s(sizeof(container_pause_request));
    if (crequest == NULL) {
        ERROR("Out of memory");
        ret = -1;
        goto out;
    }

    if (lp_request->name != NULL) {
        crequest->id = util_strdup_s(lp_request->name);
    }

    *body = container_pause_request_generate_json(crequest, &ctx, &err);
    if (*body == NULL) {
        ERROR("Failed to generate pause request json:%s", err);
        ret = -1;
        goto out;
    }
    *body_len = strlen(*body) + 1;
out:
    free(err);
    free_container_pause_request(crequest);
    return ret;
}

/* unpack pause response */
static int unpack_pause_response(const struct parsed_http_message *message, void *arg)
{
    struct isula_pause_response *pause_response = arg;
    container_pause_response *cresponse = NULL;
    parser_error err = NULL;
    int ret = 0;

    ret = check_status_code(message->status_code);
    if (ret != 0) {
        goto out;
    }

    cresponse = container_pause_response_parse_data(message->body, NULL, &err);
    if (cresponse == NULL) {
        ERROR("Invalid pause response:%s", err);
        ret = -1;
        goto out;
    }
    pause_response->server_errono = cresponse->cc;
    if (cresponse->errmsg != NULL) {
        pause_response->errmsg = util_strdup_s(cresponse->errmsg);
    }
    ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1;
    if (message->status_code == RESTFUL_RES_SERVERR) {
        ret = -1;
    }

out:
    free(err);
    free_container_pause_response(cresponse);
    return ret;
}

/* rest container pause */
static int rest_container_pause(const struct isula_pause_request *lp_request,
                                struct isula_pause_response *lp_response, void *arg)
{
    char *body = NULL;
    int ret = 0;
    size_t len = 0;
    client_connect_config_t *connect_config = (client_connect_config_t *)arg;
    const char *socketname = (const char *)(connect_config->socket);
    Buffer *output = NULL;

    ret = pause_request_to_rest(lp_request, &body, &len);
    if (ret != 0) {
        goto out;
    }
    ret = rest_send_requst(socketname, RestHttpHead ContainerServicePause, body, len, &output);
    if (ret != 0) {
        lp_response->errmsg = util_strdup_s(errno_to_error_message(ISULAD_ERR_CONNECT));
        lp_response->cc = ISULAD_ERR_EXEC;
        goto out;
    }
    ret = get_response(output, unpack_pause_response, (void *)lp_response);
    if (ret != 0) {
        goto out;
    }
out:
    if (output != NULL) {
        buffer_free(output);
    }
    put_body(body);
    return ret;
}

/* kill request to rest */
static int kill_request_to_rest(const struct isula_kill_request *lk_request, char **body, size_t *body_len)
{
    container_kill_request *crequest = NULL;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;
    int ret = 0;

    crequest = util_common_calloc_s(sizeof(container_kill_request));
    if (crequest == NULL) {
        ERROR("Out of memory");
        ret = -1;
        goto out;
    }

    if (lk_request->name != NULL) {
        crequest->id = util_strdup_s(lk_request->name);
    }
    crequest->signal = lk_request->signal;

    *body = container_kill_request_generate_json(crequest, &ctx, &err);
    if (*body == NULL) {
        ERROR("Failed to generate kill request json:%s", err);
        ret = -1;
        goto out;
    }
    *body_len = strlen(*body) + 1;
out:
    free(err);
    free_container_kill_request(crequest);
    return ret;
}

/* unpack kill response */
static int unpack_kill_response(const struct parsed_http_message *message, void *arg)
{
    struct isula_kill_response *kill_response = arg;
    container_kill_response *cresponse = NULL;
    parser_error err = NULL;
    int ret = 0;

    ret = check_status_code(message->status_code);
    if (ret != 0) {
        goto out;
    }

    cresponse = container_kill_response_parse_data(message->body, NULL, &err);
    if (cresponse == NULL) {
        ERROR("Invalid kill response:%s", err);
        ret = -1;
        goto out;
    }
    kill_response->server_errono = cresponse->cc;
    if (cresponse->errmsg != NULL) {
        kill_response->errmsg = util_strdup_s(cresponse->errmsg);
    }
    ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1;
    if (message->status_code == RESTFUL_RES_SERVERR) {
        ret = -1;
    }

out:
    free(err);
    free_container_kill_response(cresponse);
    return ret;
}

/* rest container kill */
static int rest_container_kill(const struct isula_kill_request *lk_request,
                               struct isula_kill_response *lk_response, void *arg)
{
    char *body = NULL;
    int ret = 0;
    size_t len = 0;
    client_connect_config_t *connect_config = (client_connect_config_t *)arg;
    const char *socketname = (const char *)(connect_config->socket);
    Buffer *output = NULL;

    ret = kill_request_to_rest(lk_request, &body, &len);
    if (ret != 0) {
        goto out;
    }
    ret = rest_send_requst(socketname, RestHttpHead ContainerServiceKill, body, len, &output);
    if (ret != 0) {
        lk_response->errmsg = util_strdup_s(errno_to_error_message(ISULAD_ERR_CONNECT));
        lk_response->cc = ISULAD_ERR_EXEC;
        goto out;
    }
    ret = get_response(output, unpack_kill_response, (void *)lk_response);
    if (ret != 0) {
        goto out;
    }
out:
    if (output != NULL) {
        buffer_free(output);
    }
    put_body(body);
    return ret;
}

/* remove request to rest */
static int remove_request_to_rest(const struct isula_delete_request *ld_request, char **body, size_t *body_len)
{
    container_delete_request *crequest = NULL;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;
    int ret = 0;

    crequest = util_common_calloc_s(sizeof(container_delete_request));
    if (crequest == NULL) {
        ERROR("Out of memory");
        ret = -1;
        goto out;
    }

    if (ld_request->name != NULL) {
        crequest->id = util_strdup_s(ld_request->name);
    }
    crequest->force = ld_request->force;

    *body = container_delete_request_generate_json(crequest, &ctx, &err);
    if (*body == NULL) {
        ERROR("Failed to generate remove request json:%s", err);
        ret = -1;
        goto out;
    }
    *body_len = strlen(*body) + 1;
out:
    free(err);
    free_container_delete_request(crequest);
    return ret;
}

/* unpack remove response */
static int unpack_remove_response(const struct parsed_http_message *message, void *arg)
{
    struct isula_delete_response *delete_response = arg;
    container_delete_response *cresponse = NULL;
    parser_error err = NULL;
    int ret = 0;

    ret = check_status_code(message->status_code);
    if (ret != 0) {
        goto out;
    }

    cresponse = container_delete_response_parse_data(message->body, NULL, &err);
    if (cresponse == NULL) {
        ERROR("Invalid remove response:%s", err);
        ret = -1;
        goto out;
    }
    delete_response->server_errono = cresponse->cc;
    if (cresponse->errmsg != NULL) {
        delete_response->errmsg = util_strdup_s(cresponse->errmsg);
    }
    ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1;
    if (message->status_code == RESTFUL_RES_SERVERR) {
        ret = -1;
    }

out:
    free(err);
    free_container_delete_response(cresponse);
    return ret;
}

/* rest container remove */
static int rest_container_remove(const struct isula_delete_request *ld_request,
                                 struct isula_delete_response *ld_response, void *arg)
{
    char *body = NULL;
    int ret = 0;
    size_t len;
    client_connect_config_t *connect_config = (client_connect_config_t *)arg;
    const char *socketname = (const char *)(connect_config->socket);
    Buffer *r_output = NULL;

    ret = remove_request_to_rest(ld_request, &body, &len);
    if (ret != 0) {
        goto out;
    }
    ret = rest_send_requst(socketname, RestHttpHead ContainerServiceRemove, body, len, &r_output);
    if (ret != 0) {
        ld_response->errmsg = util_strdup_s(errno_to_error_message(ISULAD_ERR_CONNECT));
        ld_response->cc = ISULAD_ERR_EXEC;
        goto out;
    }
    ret = get_response(r_output, unpack_remove_response, (void *)ld_response);
    if (ret != 0) {
        goto out;
    }
out:
    if (r_output != NULL) {
        buffer_free(r_output);
    }
    put_body(body);
    return ret;
}

/* inspect request to rest */
static int inspect_request_to_rest(const struct isula_inspect_request *li_request, char **body, size_t *body_len)
{
    container_inspect_request *crequest = NULL;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;
    int ret = 0;

    crequest = util_common_calloc_s(sizeof(container_inspect_request));
    if (crequest == NULL) {
        ERROR("Out of memory");
        ret = -1;
        goto out;
    }

    if (li_request->name != NULL) {
        crequest->id = util_strdup_s(li_request->name);
    }

    crequest->bformat = li_request->bformat;
    crequest->timeout = li_request->timeout;

    *body = container_inspect_request_generate_json(crequest, &ctx, &err);
    if (*body == NULL) {
        ERROR("Failed to generate inspect request json:%s", err);
        ret = -1;
        goto out;
    }
    *body_len = strlen(*body) + 1;
out:
    free(err);
    free_container_inspect_request(crequest);
    return ret;
}

/* unpack inspect response */
static int unpack_inspect_response(const struct parsed_http_message *message, void *arg)
{
    struct isula_inspect_response *response = arg;
    container_inspect_response *cresponse = NULL;
    parser_error err = NULL;
    int ret = 0;

    ret = check_status_code(message->status_code);
    if (ret != 0) {
        goto out;
    }

    cresponse = container_inspect_response_parse_data(message->body, NULL, &err);
    if (cresponse == NULL) {
        ERROR("Invalid inspect response:%s", err);
        ret = -1;
        goto out;
    }
    response->server_errono = cresponse->cc;
    if (cresponse->container_json != NULL) {
        response->json = util_strdup_s(cresponse->container_json);
    }
    if (cresponse->errmsg != NULL) {
        response->errmsg = util_strdup_s(cresponse->errmsg);
    }
    ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1;
    if (message->status_code == RESTFUL_RES_SERVERR) {
        ret = -1;
    }

out:
    free(err);
    free_container_inspect_response(cresponse);
    return ret;
}

/* rest container inspect */
static int rest_container_inspect(const struct isula_inspect_request *li_request,
                                  struct isula_inspect_response *li_response, void *arg)
{
    char *body = NULL;
    int ret = 0;
    size_t len;
    client_connect_config_t *connect_config = (client_connect_config_t *)arg;
    const char *socketname = (const char *)(connect_config->socket);
    Buffer *output = NULL;

    ret = inspect_request_to_rest(li_request, &body, &len);
    if (ret != 0) {
        goto out;
    }
    ret = rest_send_requst(socketname, RestHttpHead ContainerServiceInspect, body, len, &output);
    if (ret != 0) {
        li_response->errmsg = util_strdup_s(errno_to_error_message(ISULAD_ERR_CONNECT));
        li_response->cc = ISULAD_ERR_EXEC;
        goto out;
    }
    ret = get_response(output, unpack_inspect_response, (void *)li_response);
    if (ret != 0) {
        goto out;
    }
out:
    if (output != NULL) {
        buffer_free(output);
    }
    put_body(body);
    return ret;
}

/* exec request to rest */
static int exec_request_to_rest(const struct isula_exec_request *le_request, char **body, size_t *body_len)
{
    container_exec_request *crequest = NULL;
    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
    parser_error err = NULL;
    int ret = 0;

    crequest = util_common_calloc_s(sizeof(container_exec_request));
    if (crequest == NULL) {
        ERROR("Out of memory");
        ret = -1;
        goto out;
    }

    crequest->tty = le_request->tty;
    crequest->attach_stdin = le_request->attach_stdin;
    crequest->attach_stdout = le_request->attach_stdout;
    crequest->attach_stderr = le_request->attach_stderr;

    if (le_request->name != NULL) {
        crequest->container_id = util_strdup_s(le_request->name);
    }
    if (le_request->stdout != NULL) {
        crequest->stdout = util_strdup_s(le_request->stdout);
    }
    if (le_request->stdin != NULL) {
        crequest->stdin = util_strdup_s(le_request->stdin);
    }
    if (le_request->stderr != NULL) {
        crequest->stderr = util_strdup_s(le_request->stderr);
    }

    int i = 0;
    if (le_request->argc > 0) {
        if ((size_t)le_request->argc > SIZE_MAX / sizeof(char *)) {
            ERROR("Too many arguments!");
            ret = -1;
            goto out;
        }
        crequest->argv = (char **)util_common_calloc_s(sizeof(char *) * (size_t)le_request->argc);
        if (crequest->argv == NULL) {
            ERROR("Out of memory");
            ret = -1;
            goto out;
        }
        for (i = 0; i < le_request->argc; i++) {
            crequest->argv[i] = util_strdup_s(le_request->argv[i]);
        }
        crequest->argv_len = (size_t)le_request->argc;
    }
    if (le_request->env_len > 0) {
        if ((size_t)le_request->env_len > SIZE_MAX / sizeof(char *)) {
            ERROR("Too many environmental variables!");
            ret = -1;
            goto out;
        }
        crequest->env = (char **)util_common_calloc_s(sizeof(char *) * (size_t)le_request->env_len);
        if (crequest->env == NULL) {
            ERROR("Out of memory");
            ret = -1;
            goto out;
        }
        for (i = 0; i < le_request->env_len; i++) {
            crequest->env[i] = util_strdup_s(le_request->env[i]);
        }
        crequest->env_len = (size_t)le_request->env_len;
    }

    *body = container_exec_request_generate_json(crequest, &ctx, &err);
    if (*body == NULL) {
        ERROR("Failed to generate exec request json:%s", err);
        ret = -1;
        goto out;
    }
    *body_len = strlen(*body) + 1;
out:
    free(err);
    free_container_exec_request(crequest);
    return ret;
}

/* unpack exec response */
static int unpack_exec_response(const struct parsed_http_message *message, void *arg)
{
    struct isula_exec_response *response = arg;
    container_exec_response *cresponse = NULL;
    parser_error err = NULL;
    int ret = 0;

    ret = check_status_code(message->status_code);
    if (ret != 0) {
        goto out;
    }

    cresponse = container_exec_response_parse_data(message->body, NULL, &err);
    if (cresponse == NULL) {
        ERROR("Invalid exec response:%s", err);
        ret = -1;
        goto out;
    }
    response->server_errono = cresponse->cc;
    response->exit_code = cresponse->exit_code;
    if (cresponse->errmsg != NULL) {
        response->errmsg = util_strdup_s(cresponse->errmsg);
    }
    ret = (cresponse->cc == ISULAD_SUCCESS) ? 0 : -1;
    if (message->status_code == RESTFUL_RES_SERVERR) {
        ret = -1;
    }

out:
    free(err);
    free_container_exec_response(cresponse);
    return ret;
}

/* rest container exec */
static int rest_container_exec(const struct isula_exec_request *le_request,
                               struct isula_exec_response *le_response, void *arg)
{
    char *body = NULL;
    int ret = 0;
    size_t len;
    client_connect_config_t *connect_config = (client_connect_config_t *)arg;
    const char *socketname = (const char *)(connect_config->socket);
    Buffer *output = NULL;

    ret = exec_request_to_rest(le_request, &body, &len);
    if (ret != 0) {
        goto out;
    }
    ret = rest_send_requst(socketname, RestHttpHead ContainerServiceExec, body, len, &output);
    if (ret != 0) {
        le_response->errmsg = util_strdup_s(errno_to_error_message(ISULAD_ERR_CONNECT));
        le_response->cc = ISULAD_ERR_EXEC;
        goto out;
    }
    ret = get_response(output, unpack_exec_response, (void *)le_response);
    if (ret != 0) {
        goto out;
    }
out:
    if (output != NULL) {
        buffer_free(output);
    }
    put_body(body);
    return ret;
}

/* rest containers client ops init */
int rest_containers_client_ops_init(isula_connect_ops *ops)
{
    if (ops == NULL) {
        return -1;
    }

    ops->container.create = &rest_container_create;
    ops->container.start = &rest_container_start;
    ops->container.stop = &rest_container_stop;
    ops->container.restart = &rest_container_restart;
    ops->container.remove = &rest_container_remove;
    ops->container.inspect = &rest_container_inspect;
    ops->container.list = &rest_container_list;
    ops->container.exec = &rest_container_exec;
    ops->container.pause = &rest_container_pause;
    ops->container.attach = &rest_container_attach;
    ops->container.resume = &rest_container_resume;
    ops->container.update = &rest_container_update;
    ops->container.kill = &rest_container_kill;
    ops->container.version = &rest_container_version;
    ops->container.wait = &rest_container_wait;

    return 0;
}

