/*
 * Copyright 2014 Cloud Linux Zug GmbH
 *
 * Licensed under CLOUD LINUX LICENSE AGREEMENT
 * http://cloudlinux.com/docs/LICENSE.TXT
 *
 * The part the support library for lsapi & proxy_lsapi Apache modules
 * author Alexander Demeshko <ademeshko@cloudlinux.com>
 *
 */
 
#include <lscapi_util.h>

#include <http_request.h>
#include <util_script.h>

struct lscapi_server_vars_t {
    request_rec *r;
    int varNum;
    int maxVarNum;
    lscapi_var_t *vars;
};

static int processServerVar(struct lscapi_server_vars_t *vars, const char *key, const char *value) {
    if(vars->varNum >= vars->maxVarNum) {
        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, vars->r,
                      "Cannot process all server vars -- limit %d is exceeded", vars->maxVarNum);
        return 0;
    }
    
    lscapi_var_t *curVar = vars->vars + vars->varNum++;
    curVar->key = key;
    curVar->keyLen = strlen(key);
    curVar->val = value;
    curVar->valLen = strlen(value);

    return 1;
}

#define LSCAPI_SERVER_MAX_VAR_NUM 40

int lscapi_parse_server_vars(request_rec *r, lscapi_var_t **varsPtr) 
{
#if 0    
    lscapi_var_t *vars = apr_palloc(r->pool, sizeof(lscapi_var_t) * LSCAPI_SERVER_MAX_VAR_NUM);
    ap_add_common_vars(r);
    ap_add_cgi_vars(r);

    lscapi_var_t *curVar;
    const char *curKey;
    const char *curVal;
    int varNum = 0;

    curKey = "HTTP_HOST";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "HTTP_USER_AGENT";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "HTTP_ACCEPT";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "HTTP_ACCEPT_LANGUAGE";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "HTTP_ACCEPT_ENCODING";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "HTTP_REFERER";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "HTTP_COOKIE";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "HTTP_CONNECTION";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "SERVER_SIGNATURE";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "SERVER_SOFTWARE";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "SERVER_NAME";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    } else if(r->server->server_hostname) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = r->server->server_hostname;
        curVar->valLen = strlen(curVar->val);
    }

    curKey = "SERVER_ADDR";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "SERVER_PORT";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "SERVER_ADMIN";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    } else if(r->server->server_admin) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = r->server->server_admin;
        curVar->valLen = strlen(curVar->val);
    }

    curKey = "SERVER_PROTOCOL";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    } else if(r->protocol) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = r->protocol;
        curVar->valLen = strlen(curVar->val);
    }

    curKey = "REMOTE_ADDR";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
#ifndef APACHE2_2
    } else if(r->useragent_ip) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = r->useragent_ip;
        curVar->valLen = strlen(curVar->val);
#endif
    }

    curKey = "REMOTE_PORT";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
#ifndef APACHE2_2
    } else if(r->connection->client_addr) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = apr_psprintf(r->pool, "%u", r->useragent_addr->port);
        curVar->valLen = strlen(curVar->val);
#endif
    }

    curKey = "DOCUMENT_ROOT";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "CONTEXT_DOCUMENT_ROOT";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "CONTEXT_PREFIX";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "REQUEST_SCHEME";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "REQUEST_METHOD";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    } else if(r->method) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = r->method;
        curVar->valLen = strlen(curVar->val);
    }

    curKey = "REQUEST_URI";
    curVal = apr_table_get(r->subprocess_env, curKey);
    int REQUEST_URI_found = 0;
    if(curVal) {
        curVar = vars + varNum++;
            curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
        REQUEST_URI_found = 1;
    } else if(r->unparsed_uri) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = r->unparsed_uri;
        curVar->valLen = strlen(curVar->val);
        REQUEST_URI_found = 1;
    }
    
    if(REQUEST_URI_found) {
        const char *ptr = curVar->val; 
        curKey = "SCRIPT_URL";
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = ptr;
        curVar->valLen = strlen(curVar->val);
    }

    curKey = "QUERY_STRING";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    } else if(r->parsed_uri.query) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = r->parsed_uri.query;
        curVar->valLen = strlen(curVar->val);
    } else {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = "";
        curVar->valLen = 0;
    }

    char *query_copy = apr_pstrdup(r->pool, curVar->val);
    ap_unescape_url(query_copy);
    curKey = "QUERY_STRING_UNESCAPED";
    curVar = vars + varNum++;
    curVar->key = curKey;
    curVar->keyLen = strlen(curKey);
    curVar->val = ap_escape_shell_cmd(r->pool, query_copy);
    curVar->valLen = 0;


    curKey = "SCRIPT_NAME";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "SCRIPT_FILENAME";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "PATH_TRANSLATED";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }

    curKey = "PATH_INFO";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    }
    *varsPtr = vars;
    return varNum;
#else

    lscapi_var_t *vars = apr_palloc(r->pool, sizeof(lscapi_var_t) * LSCAPI_SERVER_MAX_VAR_NUM);
    struct lscapi_server_vars_t serverVars;
    serverVars.r = r;
    serverVars.maxVarNum = LSCAPI_SERVER_MAX_VAR_NUM;
    serverVars.varNum = 0;
    serverVars.vars = vars;


    ap_add_common_vars(r);
    ap_add_cgi_vars(r);

    apr_table_do((apr_table_do_callback_fn_t*)processServerVar, &serverVars, r->subprocess_env, NULL);

    *varsPtr = vars;
    return serverVars.varNum;

/*
    TODO: do we need an additional processing?
*/
/*
    curKey = "SERVER_NAME";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    } else if(r->server->server_hostname) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = r->server->server_hostname;
        curVar->valLen = strlen(curVar->val);
    }


    curKey = "SERVER_ADMIN";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    } else if(r->server->server_admin) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = r->server->server_admin;
        curVar->valLen = strlen(curVar->val);
    }

    curKey = "SERVER_PROTOCOL";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    } else if(r->protocol) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = r->protocol;
        curVar->valLen = strlen(curVar->val);
    }

    curKey = "REMOTE_ADDR";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
#ifndef APACHE2_2
    } else if(r->useragent_ip) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = r->useragent_ip;
        curVar->valLen = strlen(curVar->val);
#endif
    }

    curKey = "REMOTE_PORT";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
#ifndef APACHE2_2
    } else if(r->connection->client_addr) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = apr_psprintf(r->pool, "%u", r->useragent_addr->port);
        curVar->valLen = strlen(curVar->val);
#endif
    }

    curKey = "REQUEST_METHOD";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    } else if(r->method) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = r->method;
        curVar->valLen = strlen(curVar->val);
    }

    curKey = "REQUEST_URI";
    curVal = apr_table_get(r->subprocess_env, curKey);
    int REQUEST_URI_found = 0;
    if(curVal) {
        curVar = vars + varNum++;
            curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
        REQUEST_URI_found = 1;
    } else if(r->unparsed_uri) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = r->unparsed_uri;
        curVar->valLen = strlen(curVar->val);
        REQUEST_URI_found = 1;
    }
    
    if(REQUEST_URI_found) {
        const char *ptr = curVar->val; 
        curKey = "SCRIPT_URL";
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = ptr;
        curVar->valLen = strlen(curVar->val);
    }

    curKey = "QUERY_STRING";
    curVal = apr_table_get(r->subprocess_env, curKey);
    if(curVal) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = curVal;
        curVar->valLen = strlen(curVal);
    } else if(r->parsed_uri.query) {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = r->parsed_uri.query;
        curVar->valLen = strlen(curVar->val);
    } else {
        curVar = vars + varNum++;
        curVar->key = curKey;
        curVar->keyLen = strlen(curKey);
        curVar->val = "";
        curVar->valLen = 0;
    }

    char *query_copy = apr_pstrdup(r->pool, curVar->val);
    ap_unescape_url(query_copy);
    curKey = "QUERY_STRING_UNESCAPED";
    curVar = vars + varNum++;
    curVar->key = curKey;
    curVar->keyLen = strlen(curKey);
    curVar->val = ap_escape_shell_cmd(r->pool, query_copy);
    curVar->valLen = 0;
*/
#endif
}

int lscapi_parse_special_vars(request_rec *r, apr_hash_t *cfgH, lscapi_var_t **varsPtr) 
{
    int envNum = apr_hash_count(cfgH);
    lscapi_var_t *envs = apr_palloc(r->pool, sizeof(lscapi_var_t) * (envNum ? envNum : 1) );
    
    int i = 0;
    for(apr_hash_index_t *hi = apr_hash_first(r->pool, cfgH);
        hi && i < envNum;
        hi = apr_hash_next(hi)) {

        const char *key;
        apr_ssize_t keyLen;
        php_param_t *val;
        apr_hash_this(hi, (const void**)(&key), &keyLen, (void**)(&val));

        if(!keyLen && !val->valueLen)
            continue;

        envs[i].key = key;
        envs[i].keyLen = keyLen;
        envs[i].val = val->value;
        envs[i].valLen = val->valueLen;

        i++;
    } // for
    *varsPtr = envs;
    return i;
}
