
#include "xysdk_common.h"
#include "xysdk_http_request.h"


#define XY_CLIENT_OS_TYPE			"4"
#define VERSION_CODE				"105"
#define XY_PRODUCT_TYPE			"smart_watches"


// 添加公共参数（值是常量字符串，且不会覆盖相同参数）
#define ADD_COMMON_PARAM_CONSTANT(model, key, value) add_param(model, key, value, false, false)

//static void _exec_request(xy_http_request_model *model);
static int http_exec_request(xy_http_request_model *model);

static void add_param(xy_http_request_model *model, const char *key, const char *value, const bool overrideValue, const bool copyValue);
static void append_common_params(xy_http_request_model *model);
static int calc_encoded_params_length(xy_http_request_model *model);   // 计算参数拼接好并进行URL编码后的总长度，便于准备申请内存空间
static char* calc_sig(char *buff, xy_http_request_model *model);     // 当前签名长度固定为32位
static void get_random_nonce(char *text, uint8_t length);
static void join_http_url(char *buff, const char *baseUrl, const char *path, const XYHttpParamKeyValue *currentKeyValue);

// static void emit_http_success(xy_http_request_model *model, char* response);
// static void emit_http_failure(const char* errorMsg, xy_http_request_model *model, char* response);

static XYHttpParamKeyValue* create_key_value(const char *key, const char *value, const bool copyValue);
static void destroy_key_value(XYHttpParamKeyValue *kv);
static void destroy_key_value_list(XYHttpParamKeyValue *head);
extern int xy_api_get_sig(char *app_secret, char *str, char *data_sig);


static bool isDestroyBindPage(xy_http_request_model *model, const int callPosition)
{
    // if (model->bindPageIncreamentId > 0 && xy_manager_page_isDestroyPageIncreamentId(model->bindPageIncreamentId)) {
    //     XY_LOG_W("http bindPage destroy. %d, %d\n", callPosition, model->bindPageIncreamentId);
    //     return true;
    // }
     return false;
}


xy_http_request_model *xy_http_request_create(XYHttpFunctionSuccess successCallback, XYHttpFunctionFailure failureCallback, void *callbackContext)
{
    xy_http_request_model *model = (xy_http_request_model*)xy_common_malloc(sizeof(xy_http_request_model));
    model->baseUrl = NULL;
    model->path = NULL;
    model->method = XY_HTTP_REQUEST_METHOD_GET;
    model->paramHead = NULL;
    model->requireCamelCaseCommonParams = false;
    model->bindPageIncreamentId = 0;
    model->successCallback = successCallback;
    model->failureCallback = failureCallback;
    model->responseIntercept = NULL;
    model->callbackContext = callbackContext;
    model->jsonBody = NULL;
    model->_tokenIntercept = NULL;
    model->response_buff = NULL;
    return model;
}

void xy_http_request_setBaseUrl(xy_http_request_model *model, const char *baseUrl)
{
    model->baseUrl = baseUrl;     // URL为字符串常量，只用拷贝指针，也不用额外释放
}

void xy_http_request_setPath(xy_http_request_model *model, const char *path)
{
    model->path = path;     // 路径为字符串常量，只用拷贝指针，也不用额外释放
}

void xy_http_request_setMethod(xy_http_request_model *model, const xy_http_request_method method)
{
    model->method = method;
}

void xy_http_request_addParam(xy_http_request_model *model, const char *key, const char *value)
{
    add_param(model, key, value, true, true);
}

static void add_param(xy_http_request_model *model, const char *key, const char *value, const bool overrideValue, const bool copyValue)
{
    XYHttpParamKeyValue *newKeyValue = create_key_value(key, value, copyValue);

    if (model->paramHead == NULL) {
        model->paramHead = newKeyValue;
    } else {
        XYHttpParamKeyValue *prev = NULL;
        XYHttpParamKeyValue *current = model->paramHead;

        // 在插入链表时进行排序，如果key名相同则覆盖之前的值
        while (current != NULL) {
            int cmp = strcmp(key, current->key);
            if (cmp == 0) {     // 键相同，更新值
                if (overrideValue) {
                    if (copyValue) {
                        if (!current->copyValue) {      // 如果之前的值非拷贝，置空，避免下面会删除之前的值
                            current->value = NULL;
                        }
                        xy_set_string_ptr(&current->value, value);
                    } else {
                        current->value = (char*) value;
                    }
                }
                destroy_key_value(newKeyValue);
                return;
            } else if (cmp < 0) {
                // 如果键小于当前节点的键，插入在当前节点之前
                if (prev == NULL) {
                    newKeyValue->next = model->paramHead;
                    model->paramHead = newKeyValue;
                } else {
                    newKeyValue->next = current;
                    prev->next = newKeyValue;
                }
                return;
            }

            prev = current;
            current = current->next;
        }

        // 如果遍历完列表仍未插入，插入到列表末尾
        prev->next = newKeyValue;
    }
}

void xy_http_request_requireCamelCaseCommonParams(xy_http_request_model *model, const bool require)
{
    model->requireCamelCaseCommonParams = require;
}

int xy_http_request_request(xy_http_request_model *model)
{
    // 将网络请求丢到异步线程的任务中，按队列顺序执行
    //xy_manager_task_add((XYTaskFunction)_exec_request, model, 0, 0);
    return http_exec_request(model);
}

void xy_http_request_requestDelay(xy_http_request_model *model, const int delayMS)
{
    // 将网络请求丢到异步线程的任务中，按队列顺序执行
   // xy_manager_task_add((XYTaskFunction)_exec_request, model, delayMS, xy_http_request_PriorityMedium);
}

void xy_http_request_requestDelayPriority(xy_http_request_model *model, const int delayMS, const xy_http_request_Priority priority)
{
    // 将网络请求丢到异步线程的任务中，按队列顺序执行
    //xy_manager_task_add((XYTaskFunction)_exec_request, model, delayMS, priority);
}

void xy_http_request_bindPageIncreamentId(xy_http_request_model *model, const uint32_t increamentId)
{
    model->bindPageIncreamentId = increamentId;
}

void xy_http_request_setResponseIntercept(xy_http_request_model *model, XYHttpFunctionResponseIntercept responseIntercept)
{
    model->responseIntercept = responseIntercept;
}

void xy_http_request_setJsonBody(xy_http_request_model *model, char *json)
{
    model->jsonBody = json;
}

#if 0
static void _exec_request(xy_http_request_model *model)
{
    const char *baseUrl = (model->baseUrl != NULL ? model->baseUrl : XIMALAYA_BASE_URL);
    char *httpUrl = NULL;
    char* response = NULL;
    int responseCode = 200;     // http 的服务器返回码
    int ret = XY_HTTP_OK;
    // 计算好拼接参数所需要的空间，并申请相应长度的内存空间
    int paramsLength = 0;
    int urlLength = 0;    
    char *sig = NULL;
    char errorMsg[20] = {0};

    if (isDestroyBindPage(model, 1)) {
        xy_http_request_destroy(model);
        return;
    }

    // 如果被拦截了，拦截器中执行完成后会再回调回来，所以这里不用做什么事直接返回就好
    // if (model->_tokenIntercept != NULL && !xy_http_intercept_token_canStartRequest(model->_tokenIntercept)) {
    //     return;
    // }

    

    append_common_params(model);
    xy_http_request_removeParam(model, "sig");      // 可能更新token后的第二次请求，所以先移除sig

    // 计算好拼接参数所需要的空间，并申请相应长度的内存空间
    paramsLength = calc_encoded_params_length(model);
    urlLength = strlen(baseUrl) + strlen(model->path) + paramsLength + 37 + 2 + 10;      // 37=strlen(&sig=7532dab98f6ab2a803699dc3e54d531c)，2=?\0，10=冗余
    httpUrl = xy_common_malloc(urlLength);
    if (httpUrl == NULL) {
        ret = XY_HTTP_MALLOC_ERR;
        goto Final;
    }

    // 计算签名，复用前面申请好的空间，以提高效率
    sig = calc_sig(httpUrl, model);
    if (sig == NULL) {
        ret = XY_HTTP_PARAM_NULL;
        goto Final;
    }
    xy_http_request_addParam(model, "sig", sig);
    xy_common_free((void**)&sig);

    // 拼接URL和参数： ${baseUrl}${path}?${params}
    join_http_url(httpUrl, baseUrl, model->path, model->paramHead);

    XY_LOG_I("XmHttp---> %s %s \n", (model->method == XY_HTTP_REQUEST_METHOD_POST ? "POST" : "GET"), httpUrl);
    if (model->jsonBody != NULL) {
        XY_LOG_D("Body: %s\n", model->jsonBody);
    }

    if(model->response_buff == NULL)
    {
        model->response_buff = (XYHttpResponseData *)xy_common_malloc(sizeof(XYHttpResponseData));
        if(model->response_buff == NULL)
        {
            ret = XY_HTTP_MALLOC_ERR;
            goto Final;
        }
    }

    if (model->method == XY_HTTP_REQUEST_METHOD_POST && model->jsonBody != NULL) 
    {
        ret = xy_api_http_post_request(httpUrl, true, model->jsonBody, strlen(model->jsonBody), model->response_buff);
    } 
    else if (model->method == XY_HTTP_REQUEST_METHOD_POST) 
    {
        ret = xy_api_http_post_request(httpUrl, false, NULL, 0, model->response_buff);
    } 
    else 
    {
        ret = xy_api_http_get_request(httpUrl, model->response_buff);
    }

    XY_LOG_D("http_request_ret: %d\n", ret);

Final:
    xy_common_free((void**)&httpUrl);

    // 若页面已销毁，不再回调，避免页面逻辑错误
    if (isDestroyBindPage(model, 2)) {
        xy_http_request_destroy(model);
        return;
    }

    // 拦截 Token 是否失效
    // if (model->_tokenIntercept != NULL && !xy_http_intercept_token_canFinshRequest(model->_tokenIntercept, model->response_buff, responseCode)) {
    //     return;
    // }

    // 在默认的判断成功或失败之前，拦截网络的结果返回
    // if (model->responseIntercept != NULL && model->responseIntercept(model->callbackContext, model->response_buff, responseCode)) {
    //     xy_http_request_destroy(model);
    //     return;
    // }

    if (0 != ret || NULL == model->response_buff) {
        snprintf(errorMsg, 20, "E1 ret=%d", ret);
        emit_http_failure(errorMsg, model, model->response_buff->data);
        return;
    }

    emit_http_success(model, model->response_buff->data);
}
#endif

static int http_exec_request(xy_http_request_model *model)
{
    const char *baseUrl = (model->baseUrl != NULL ? model->baseUrl : XIMALAYA_BASE_URL);
    char *httpUrl = NULL;
    //char* response = NULL;
    //int responseCode = 200;     // http 的服务器返回码
    int ret = XY_HTTP_OK;
    // 计算好拼接参数所需要的空间，并申请相应长度的内存空间
    int paramsLength = 0;
    int urlLength = 0;    
    char *sig = NULL;
    //char errorMsg[20] = {0};

    if (isDestroyBindPage(model, 1)) 
    {
        return XY_HTTP_BREAK;
    }

    // 如果被拦截了，拦截器中执行完成后会再回调回来，所以这里不用做什么事直接返回就好
    // if (model->_tokenIntercept != NULL && !xy_http_intercept_token_canStartRequest(model->_tokenIntercept)) {
    //     return XY_HTTP_TOKEN_INVALID;
    // }

    

    append_common_params(model);
    xy_http_request_removeParam(model, "sig");      // 可能更新token后的第二次请求，所以先移除sig

    // 计算好拼接参数所需要的空间，并申请相应长度的内存空间
    paramsLength = calc_encoded_params_length(model);
    urlLength = strlen(baseUrl) + strlen(model->path) + paramsLength + 37 + 2 + 10;      // 37=strlen(&sig=7532dab98f6ab2a803699dc3e54d531c)，2=?\0，10=冗余
    httpUrl = xy_common_big_mem_malloc(urlLength);
    if (httpUrl == NULL) {
        ret = XY_HTTP_MALLOC_ERR;
        goto Final;
    }

    // 计算签名，复用前面申请好的空间，以提高效率
    sig = calc_sig(httpUrl, model);
    if (sig == NULL) {
        ret = XY_HTTP_PARAM_NULL;
        goto Final;
    }
    xy_http_request_addParam(model, "sig", sig);
    xy_common_free((void**)&sig);

    // 拼接URL和参数： ${baseUrl}${path}?${params}
    join_http_url(httpUrl, baseUrl, model->path, model->paramHead);

    XY_LOG_I("XmHttp---> %s %s \n", (model->method == XY_HTTP_REQUEST_METHOD_POST ? "POST" : "GET"), httpUrl);
    if (model->jsonBody != NULL) {
        XY_LOG_D("Body: %s\n", model->jsonBody);
    }

    if(model->response_buff == NULL)
    {
        model->response_buff = (XYHttpResponseData *)xy_common_big_mem_malloc(sizeof(XYHttpResponseData));
        if(model->response_buff == NULL)
        {
            ret = XY_HTTP_MALLOC_ERR;
            goto Final;
        }
    }

    if (model->method == XY_HTTP_REQUEST_METHOD_POST && model->jsonBody != NULL) 
    {
        ret = xy_api_http_post_request(httpUrl, true, model->jsonBody, strlen(model->jsonBody), model->response_buff);
    } 
    else if (model->method == XY_HTTP_REQUEST_METHOD_POST) 
    {
        ret = xy_api_http_post_request(httpUrl, false, NULL, 0, model->response_buff);
    } 
    else 
    {
        ret = xy_api_http_get_request(httpUrl, model->response_buff);
    }

    XY_LOG_D("http_request_ret: %d\n", ret);

Final:
    xy_common_big_mem_free((void**)&httpUrl);

    // 若页面已销毁，不再回调，避免页面逻辑错误
    if (isDestroyBindPage(model, 2)) {
        return XY_HTTP_BREAK;
    }
    
    // 拦截 Token 是否失效
    // if (model->_tokenIntercept != NULL && !xy_http_intercept_token_canFinshRequest(model->_tokenIntercept, model->response_buff, responseCode)) {
    //     return XY_HTTP_TOKEN_INVALID;
    // }

    // 在默认的判断成功或失败之前，拦截网络的结果返回
    // if (model->responseIntercept != NULL && model->responseIntercept(model->callbackContext, model->response_buff, responseCode)) {
    //     return XY_HTTP_BREAK;
    // }

#if 0
    if (0 != ret || NULL == model->response_buff) {
        snprintf(errorMsg, 20, "E1 ret=%d", ret);
        emit_http_failure(errorMsg, model, model->response_buff->data);
        return;
    }

    emit_http_success(model, model->response_buff->data);
#endif
    if(model->response_buff)
    {
        XY_LOG_D("len: %ld, %.*s \n", model->response_buff->length, 500, model->response_buff->data);    // 固定打印前500个字符
    }
    XY_LOG_D("http===%s, ret: %d",model->path, ret);    // 固定打印前500个字符
    return ret;
}

#if 0
void xy_http_request_addTokenParam(xy_http_request_model *model, const char *key, const xy_http_request_TokenType tokenType)
{
    xy_http_intercept_token_model *tokenModel = model->_tokenIntercept;
    if (tokenModel == NULL) {
        tokenModel = (xy_http_intercept_token_model*)xy_common_malloc(sizeof(xy_http_intercept_token_model));
        if (tokenModel == NULL) {
            return;
        }
        tokenModel->httpRequest = model;
        tokenModel->refreshCount = 0;
        tokenModel->isEmptyTokenValue = true;
        tokenModel->emitHttpFailure = emit_http_success;
        model->_tokenIntercept = tokenModel;
    }
    xy_utils_setString(tokenModel->tokenKey, key, sizeof(tokenModel->tokenKey));
    tokenModel->tokenType = tokenType;
    xy_http_intercept_token_addParam(tokenModel);
}
#endif

#if 0
static void emit_http_success(xy_http_request_model *model, char *response)
{
    XY_LOG_D("XmHttp<--- %s; %.*s \n", model->path, 500, response);    // 固定打印前500个字符
    if (model->successCallback) {
        model->successCallback(model->callbackContext, response);
    }
    xy_http_request_destroy(model);
}

static void emit_http_failure(const char *errorMsg, xy_http_request_model *model, char *response)
{
    XY_LOG_W("XmHttp<--- %s; error: %s, %s \n", model->path, errorMsg, response);
    if (model->failureCallback) {
        model->failureCallback(model->callbackContext, xy_res_type_CodeNetworkError);
    }
    xy_http_request_destroy(model);
}
#endif
static void append_common_params(xy_http_request_model *model)
{
    char nonce[11] = {0};
    char uid[11] = {0};
    get_random_nonce(nonce, sizeof(nonce) - 1);
    // 按照 key 倒序写，可减少函数中的插入循环次数
    ADD_COMMON_PARAM_CONSTANT(model, "version_code", VERSION_CODE);
    ADD_COMMON_PARAM_CONSTANT(model, "version", VERSION_CODE);
    if (xy_common_get_uid() > 0) {      // 用户ID非空时才传入
        snprintf(uid, sizeof(uid), "%d", xy_common_get_uid());
        xy_http_request_addParam(model, "uid", uid);
    }
    xy_http_request_addParam(model, "timestamp", xy_api_get_timestamp_ms_str());
    ADD_COMMON_PARAM_CONSTANT(model, "sn", xy_api_get_app_sn());
    ADD_COMMON_PARAM_CONSTANT(model, "product_type", XY_PRODUCT_TYPE);
    xy_http_request_addParam(model, "nonce", nonce);
    ADD_COMMON_PARAM_CONSTANT(model, "device_id_type", "UUID");
    ADD_COMMON_PARAM_CONSTANT(model, "device_id", xy_api_get_device_id());
    ADD_COMMON_PARAM_CONSTANT(model, "client_os_type", XY_CLIENT_OS_TYPE);
    ADD_COMMON_PARAM_CONSTANT(model, "app_key", xy_api_get_appkey());

    // 只有部分接口需要驼峰命名的公共参数，以减少不必要的内存开销
    if (model->requireCamelCaseCommonParams) {
        ADD_COMMON_PARAM_CONSTANT(model, "productType", XY_PRODUCT_TYPE);  // 会兼容首页的多行卡片
        ADD_COMMON_PARAM_CONSTANT(model, "deviceId", xy_api_get_device_id());
        ADD_COMMON_PARAM_CONSTANT(model, "clientOsType", XY_CLIENT_OS_TYPE);
        ADD_COMMON_PARAM_CONSTANT(model, "appKey", xy_api_get_appkey());
    }
}


static XYHttpParamKeyValue *create_key_value(const char *key, const char *value, const bool copyValue)
{
    XYHttpParamKeyValue *kv = (XYHttpParamKeyValue*)xy_common_malloc(sizeof(XYHttpParamKeyValue));
    kv->key = key;
    kv->next = NULL;
    if (copyValue) {
        kv->value = NULL;
        xy_set_string_ptr(&kv->value, value);
    } else {
        kv->value = (char*) value;    // 此种情况时 value 为常量字符串
    }
    kv->copyValue = copyValue;
    return kv;
}

static void destroy_key_value(XYHttpParamKeyValue *kv)
{
    if (kv->copyValue) {        // 当值是拷贝（malloc()的新空间存储的）时，才需要释放
        xy_common_free((void**)&kv->value);
    }
    xy_common_free((void**)&kv);
}

void destroy_key_value_list(XYHttpParamKeyValue *head)
{
    XYHttpParamKeyValue *current = head;
    while (current != NULL) {
        XYHttpParamKeyValue *next = current->next;
        destroy_key_value(current);
        current = next;
    }
}

static void get_random_nonce(char *text, uint8_t length)
{
    static const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    int index = 0;
    int i;
    for (i = 0; i < length; i++) {
        index = rand() % (sizeof(charset) - 1);
        text[i] = charset[index];
    }
    text[length] = '\0'; // 添加字符串结束标志
}

static int calc_encoded_params_length(xy_http_request_model *model)
{
    int totalLength = 0;
    bool isFirstParam = true;
    int i;
    XYHttpParamKeyValue *currentKeyValue = model->paramHead;
    const char *value = NULL;
    int valueLength = 0;
    int specialCharCount = 0;
    int c =0;
    while (currentKeyValue != NULL) {
        if (!isFirstParam) {
            totalLength += 1;   // '&'
        }
        totalLength += strlen(currentKeyValue->key);
        totalLength += 1;       // '='

        // 找需要进行编码字符的个数，用三倍关系计算编码后的长度
        value = currentKeyValue->value;
        valueLength = strlen(value);
        specialCharCount = 0;
        for (i = 0; i < valueLength; i++) {
            c = value[i];
            if (!(isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~' || c == ' ')) {
                specialCharCount++;
            }
        }
        totalLength += (valueLength + (specialCharCount * 2));  // 每个字符编码后长度多两个，如：& -> %26， 你 -> %E4%BD%A0 (strlen("你") = 3)

        isFirstParam = false;
        currentKeyValue = currentKeyValue->next;
    }
    return totalLength;
}

static char* calc_sig(char *buff, xy_http_request_model *model)
{
    bool isFirstParam = true;
    XYHttpParamKeyValue *currentKeyValue = model->paramHead;
    char *index = buff;
    char *sig = (char*)xy_common_malloc(32+1);
    int ret=-1;
    if(sig==NULL)
    {
        return NULL;
    }

    while (currentKeyValue != NULL) {
        if (!isFirstParam) {
            index[0] = '&';
            index += 1;
        }
        memcpy(index, currentKeyValue->key, strlen(currentKeyValue->key));
        index += strlen(currentKeyValue->key);

        index[0] = '=';
        index += 1;

        memcpy(index, currentKeyValue->value, strlen(currentKeyValue->value));
        index += strlen(currentKeyValue->value);

        isFirstParam = false;
        currentKeyValue = currentKeyValue->next;
    }
    index[0] = '\0';
    XY_LOG_I("xy_api_get_sig buff=%s\n", buff);
    ret = xy_api_get_sig(xy_api_get_appsecret(), buff, sig);
    XY_LOG_I("xy_api_get_sig ret=%d\n",ret);
    if(ret != 0)
    {
        xy_common_free((void**)&sig);
        sig = NULL;
        return NULL;
    }
    XY_LOG_I("calc_sig sig = %s\n", sig);
    return sig;
}

void xy_http_request_destroy(xy_http_request_model *model)
{
    if (!model) return;
    xy_common_free((void**)&model->jsonBody);
    xy_common_free((void**)&model->_tokenIntercept);
    xy_common_big_mem_free((void**)&model->response_buff);
    if (model->paramHead)
        destroy_key_value_list(model->paramHead);
    xy_common_free((void**)&model);
}

char *xy_http_request_encodeURL(const char *sourceURL)
{
    int len = strlen(sourceURL);
    int count = 0;
    int i;
    static const char *hex = "0123456789ABCDEF";
    int encoded_len = 0;
    char *encoded = NULL;
    int pos = 0;

    // 第一次循环，计算需要编码的字符数量
    for (i = 0; i < len; i++) {
        int c = sourceURL[i];
        if (!(isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~' || c == ' ')) {
            count++;
        }
    }

    // 若没有要编码的字符串，直接返回
    if (count == 0) {
        return NULL;
    }

    // 计算编码后的字符串长度
    encoded_len = len + count * 2;
    encoded = xy_common_big_mem_malloc(encoded_len + 1); // 分配足够的内存

    // 第二次循环，进行编码
    for (i = 0; i < len; i++) {
        int c = sourceURL[i];       // 在编译器上报错，所以从char改成int，错误：array subscript has type 'char' [-Werror=char-subscripts]

        if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~' || c == ' ') {
            encoded[pos++] = c;
        } else {
            encoded[pos++] = '%';
            encoded[pos++] = hex[(c >> 4) & 0xF];
            encoded[pos++] = hex[c & 0xF];
        }
    }

    encoded[pos] = '\0';
    return encoded;
}

static void join_http_url(char *buff, const char *baseUrl, const char *path, const XYHttpParamKeyValue *currentKeyValue)
{
    char *index = buff;
    bool isFirstParam = true;
    char *encodedURL = NULL;

    memcpy(index, baseUrl, strlen(baseUrl));
    index += strlen(baseUrl);

    memcpy(index, path, strlen(path));
    index += strlen(path);

    index[0] = '?';
    index += 1;

    
    while (currentKeyValue != NULL) {
        if (!isFirstParam) {
            index[0] = '&';
            index += 1;
        }

        memcpy(index, currentKeyValue->key, strlen(currentKeyValue->key));
        index += strlen(currentKeyValue->key);

        index[0] = '=';
        index += 1;

        encodedURL = xy_http_request_encodeURL(currentKeyValue->value);
        if (encodedURL != NULL) {
            memcpy(index, encodedURL, strlen(encodedURL));
            index += strlen(encodedURL);
            xy_common_big_mem_free((void**)&encodedURL);
        } else {
            memcpy(index, currentKeyValue->value, strlen(currentKeyValue->value));
            index += strlen(currentKeyValue->value);
        }

        isFirstParam = false;
        currentKeyValue = currentKeyValue->next;
    }
    index[0] = '\0';
}

bool xy_http_request_removeParam(xy_http_request_model *model, const char *key)
{
    XYHttpParamKeyValue *prev = NULL;
    XYHttpParamKeyValue *current = model->paramHead;
    while (current != NULL) {
        if (strcmp(current->key, key) == 0) {
            if (prev == NULL) {
                model->paramHead = current->next;
            } else {
                prev->next = current->next;
            }
            destroy_key_value(current);
            return true;
        }
        prev = current;
        current = current->next;
    }
    return false;
}
