added qse_env_append() and related functions.

fixed how to handle multiple values with the same key when setting an environment variable for a cgi script
This commit is contained in:
hyung-hwan 2014-10-11 14:33:26 +00:00
parent 0f229c15f5
commit bd64702fd4
5 changed files with 200 additions and 50 deletions

View File

@ -143,6 +143,20 @@ QSE_EXPORT int qse_env_insertmbsa (
const qse_mchar_t* value[]
);
/**
* The qse_env_appendwcs() function appends an extra value to the last item
* in the environment list.
*/
int qse_env_appendwcs (
qse_env_t* env,
const qse_wchar_t* value
);
int qse_env_appendmbs (
qse_env_t* env,
const qse_mchar_t* value
);
QSE_EXPORT int qse_env_deletewcs (
qse_env_t* env,
const qse_wchar_t* name
@ -156,10 +170,12 @@ QSE_EXPORT int qse_env_deletembs (
#if defined(QSE_CHAR_IS_MCHAR)
# define qse_env_insert(env,name,value) qse_env_insertmbs(env,name,value)
# define qse_env_inserta(env,name,value) qse_env_insertmbsa(env,name,value)
# define qse_env_append(env,value) qse_env_appendmbs(env,value)
# define qse_env_delete(env,name) qse_env_deletembs(env,name)
#else
# define qse_env_insert(env,name,value) qse_env_insertwcs(env,name,value)
# define qse_env_inserta(env,name,value) qse_env_insertwcsa(env,name,value)
# define qse_env_append(env,value) qse_env_appendwcs(env,value)
# define qse_env_delete(env,name) qse_env_deletewcs(env,name)
#endif

View File

@ -182,12 +182,10 @@ static int insertw (qse_env_t* env, const qse_wchar_t* name, const qse_wchar_t*
nl = qse_wcslen (name);
for (i = 0, vl = 0; value[i]; i++) vl += qse_wcslen(value[i]);
if (env->arr.len >= env->arr.capa &&
expandarr(env) <= -1) return -1;
if (env->arr.len >= env->arr.capa && expandarr(env) <= -1) return -1;
tl = nl + 1 + vl + 1; /* name = value '\0' */
if (env->str.len + tl > env->str.capa &&
expandstr (env, tl) <= -1) return -1;
if (env->str.len + tl > env->str.capa && expandstr (env, tl) <= -1) return -1;
env->arr.ptr[env->arr.len++] = &env->str.ptr[env->str.len];
env->arr.ptr[env->arr.len] = QSE_NULL;
@ -201,16 +199,42 @@ static int insertw (qse_env_t* env, const qse_wchar_t* name, const qse_wchar_t*
return 0;
}
static int appendw (qse_env_t* env, const qse_wchar_t* value[])
{
/* append more values to the last item in the environment */
qse_size_t vl, i;
/* no item in the environment */
if (env->arr.len <= 0) return -1;
QSE_ASSERT (env->str.len > 0);
/* get the length of the values concatenated */
for (i = 0, vl = 0; value[i]; i++) vl += qse_wcslen(value[i]);
/* expand the string buffer if it's not large enough to hold additional values */
if (env->str.len + vl > env->str.capa && expandstr (env, vl) <= -1) return -1;
env->str.len--; /* decrement to override the terminating null */
/* copy additional values */
for (i = 0; value[i]; i++)
env->str.len += qse_wcscpy (&env->str.ptr[env->str.len], value[i]);
/* terminate the string buffer */
env->str.ptr[++env->str.len] = QSE_WT('\0');
return 0;
}
static int add_envstrw (qse_env_t* env, const qse_wchar_t* nv)
{
qse_size_t tl;
if (env->arr.len >= env->arr.capa &&
expandarr(env) <= -1) return -1;
if (env->arr.len >= env->arr.capa && expandarr(env) <= -1) return -1;
tl = qse_wcslen(nv) + 1;
if (env->str.len + tl > env->str.capa &&
expandstr (env, tl) <= -1) return -1;
if (env->str.len + tl > env->str.capa && expandstr (env, tl) <= -1) return -1;
env->arr.ptr[env->arr.len++] = &env->str.ptr[env->str.len];
env->arr.ptr[env->arr.len] = QSE_NULL;
@ -262,12 +286,10 @@ static int insertm (qse_env_t* env, const qse_mchar_t* name, const qse_mchar_t*
nl = qse_mbslen (name);
for (i = 0, vl = 0; value[i]; i++) vl += qse_mbslen(value[i]);
if (env->arr.len >= env->arr.capa &&
expandarr(env) <= -1) return -1;
if (env->arr.len >= env->arr.capa && expandarr(env) <= -1) return -1;
tl = nl + 1 + vl + 1; /* name = value '\0' */
if (env->str.len + tl > env->str.capa &&
expandstr (env, tl) <= -1) return -1;
if (env->str.len + tl > env->str.capa && expandstr (env, tl) <= -1) return -1;
env->arr.ptr[env->arr.len++] = &env->str.ptr[env->str.len];
env->arr.ptr[env->arr.len] = QSE_NULL;
@ -281,16 +303,42 @@ static int insertm (qse_env_t* env, const qse_mchar_t* name, const qse_mchar_t*
return 0;
}
static int appendm (qse_env_t* env, const qse_mchar_t* value[])
{
/* append more values to the last item in the environment */
qse_size_t vl, i;
/* no item in the environment */
if (env->arr.len <= 0) return -1;
QSE_ASSERT (env->str.len > 0);
/* get the length of the values concatenated */
for (i = 0, vl = 0; value[i]; i++) vl += qse_mbslen(value[i]);
/* expand the string buffer if it's not large enough to hold additional values */
if (env->str.len + vl > env->str.capa && expandstr (env, vl) <= -1) return -1;
env->str.len--; /* decrement to override the terminating null */
/* copy additional values */
for (i = 0; value[i]; i++)
env->str.len += qse_mbscpy (&env->str.ptr[env->str.len], value[i]);
/* terminate the string buffer */
env->str.ptr[++env->str.len] = QSE_MT('\0');
return 0;
}
static int add_envstrm (qse_env_t* env, const qse_mchar_t* nv)
{
qse_size_t tl;
if (env->arr.len >= env->arr.capa &&
expandarr(env) <= -1) return -1;
if (env->arr.len >= env->arr.capa && expandarr(env) <= -1) return -1;
tl = qse_mbslen(nv) + 1;
if (env->str.len + tl > env->str.capa &&
expandstr (env, tl) <= -1) return -1;
if (env->str.len + tl > env->str.capa && expandstr (env, tl) <= -1) return -1;
env->arr.ptr[env->arr.len++] = &env->str.ptr[env->str.len];
env->arr.ptr[env->arr.len] = QSE_NULL;
@ -363,6 +411,26 @@ static QSE_INLINE int insert_wcs (
#endif
}
static QSE_INLINE int append_wcs (qse_env_t* env, const qse_wchar_t* value[])
{
#if defined(QSE_ENV_CHAR_IS_WCHAR)
/* no conversion -> wchar */
return appendw (env, name, value);
#else
/* convert wchar to mchar */
qse_mchar_t* valuedup[2];
int n;
valuedup[0] = qse_wcsatombsdup (value, QSE_NULL, env->mmgr); /* TODO: ignore mbwcerr */
if (valuedup == QSE_NULL) return -1;
valuedup[1] = QSE_NULL;
n = appendm (env, valuedup);
QSE_MMGR_FREE (env->mmgr, valuedup[0]);
return n;
#endif
}
static QSE_INLINE int insert_mbs (
qse_env_t* env, const qse_mchar_t* name, const qse_mchar_t* value[])
{
@ -389,7 +457,26 @@ static QSE_INLINE int insert_mbs (
/* no conversion -> mchar */
return insertm (env, name, value);
#endif
}
static QSE_INLINE int append_mbs (qse_env_t* env, const qse_mchar_t* value[])
{
#if defined(QSE_ENV_CHAR_IS_WCHAR)
/* convert mchar to wchar */
qse_wchar_t* valuedup[2];
int n;
valuedup[0] = qse_mbsatowcsalldup (value, QSE_NULL, env->mmgr);
if (valuedup[0] == QSE_NULL) return -1;
valuedup[1] = QSE_NULL;
n = appendw (env, namedup, valuedup);
QSE_MMGR_FREE (env->mmgr, valuedup[0]);
return n;
#else
/* no conversion -> mchar */
return appendm (env, value);
#endif
}
#if defined(_WIN32)
@ -629,7 +716,7 @@ done:
qse_wchar_t* dup;
int n;
dup = qse_mbstowcsdup (*p, env->mmgr); /* TODO: ignroe mbwcerr */
dup = qse_mbstowcsdup (*p, env->mmgr); /* TODO: ignore mbwcerr */
if (dup == QSE_NULL) return -1;
n = add_envstrw (env, dup);
QSE_MMGR_FREE (env->mmgr, dup);
@ -703,6 +790,22 @@ int qse_env_insertmbsa (
return value? insert_mbs (env, name, value): insert_sys_mbs (env, name);
}
int qse_env_appendwcs (qse_env_t* env, const qse_wchar_t* value)
{
const qse_wchar_t* va[2];
va[0] = value;
va[1] = QSE_NULL;
return append_wcs (env, va);
}
int qse_env_appendmbs (qse_env_t* env, const qse_mchar_t* value)
{
const qse_mchar_t* va[2];
va[0] = value;
va[1] = QSE_NULL;
return append_mbs (env, va);
}
int qse_env_deletewcs (qse_env_t* env, const qse_wchar_t* name)
{
#if defined(QSE_ENV_CHAR_IS_WCHAR)

View File

@ -111,8 +111,6 @@ struct cgi_client_req_hdr_ctx_t
qse_env_t* env;
};
static int cgi_capture_client_header (
qse_htre_t* req, const qse_mchar_t* key, const qse_htre_hdrval_t* val, void* ctx)
{
@ -140,8 +138,6 @@ static int cgi_capture_client_header (
if (*ptr == QSE_MT('-')) *ptr = '_';
}
/* insert the last value only */
while (val->next) val = val->next;
ret = qse_env_insertmbs (hdrctx->env, http_key, val->ptr);
if (ret <= -1)
{
@ -149,8 +145,18 @@ static int cgi_capture_client_header (
hdrctx->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
}
QSE_MMGR_FREE (req->mmgr, http_key);
/* append values with the same key */
while ((val = val->next))
{
if (qse_env_appendmbs (hdrctx->env, QSE_MT(", ")) <= -1 ||
qse_env_appendmbs (hdrctx->env, val->ptr) <= -1)
{
hdrctx->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
}
}
}
return 0;
@ -442,19 +448,20 @@ static int cgi_add_env (
qparam = qse_htre_getqparam(req);
#ifdef _WIN32
qse_env_insert (env, QSE_T("PATH"), QSE_NULL);
if (qse_env_insert (env, QSE_T("PATH"), QSE_NULL) <= -1) goto oops_nomem;
#else
qse_env_insertmbs (env, QSE_MT("LANG"), QSE_NULL);
qse_env_insertmbs (env, QSE_MT("PATH"), QSE_NULL);
if (qse_env_insertmbs (env, QSE_MT("LANG"), QSE_NULL) <= -1 ||
qse_env_insertmbs (env, QSE_MT("PATH"), QSE_NULL)) goto oops_nomem;
#endif
qse_env_insertmbs (env, QSE_MT("GATEWAY_INTERFACE"), QSE_MT("CGI/1.1"));
if (qse_env_insertmbs (env, QSE_MT("GATEWAY_INTERFACE"), QSE_MT("CGI/1.1")) <= -1) goto oops_nomem;
qse_mbsxfmt (buf, QSE_COUNTOF(buf), QSE_MT("HTTP/%d.%d"), (int)v->major, (int)v->minor);
qse_env_insertmbs (env, QSE_MT("SERVER_PROTOCOL"), buf);
if (qse_env_insertmbs (env, QSE_MT("SERVER_PROTOCOL"), buf) <= -1) goto oops_nomem;
if (qse_env_insertmbs (env, QSE_MT("SCRIPT_FILENAME"), path) <= -1 ||
qse_env_insertmbs (env, QSE_MT("SCRIPT_NAME"), script) <= -1 ||
qse_env_insertmbs (env, QSE_MT("DOCUMENT_ROOT"), root) <= -1) goto oops_nomem;
qse_env_insertmbs (env, QSE_MT("SCRIPT_FILENAME"), path);
qse_env_insertmbs (env, QSE_MT("SCRIPT_NAME"), script);
qse_env_insertmbs (env, QSE_MT("DOCUMENT_ROOT"), root);
if (suffix && suffix[0] != QSE_MT('\0'))
{
const qse_mchar_t* tmp[3];
@ -468,40 +475,50 @@ static int cgi_add_env (
if (tr)
{
qse_canonmbspath (tr, tr, 0);
qse_env_insertmbs (env, QSE_MT("PATH_TRANSLATED"), tr);
if (qse_env_insertmbs (env, QSE_MT("PATH_TRANSLATED"), tr) <= -1)
{
QSE_MMGR_FREE (httpd->mmgr, tr);
goto oops_nomem;
}
QSE_MMGR_FREE (httpd->mmgr, tr);
}
qse_env_insertmbs (env, QSE_MT("PATH_INFO"), suffix);
if (qse_env_insertmbs (env, QSE_MT("PATH_INFO"), suffix) <= -1) goto oops_nomem;
}
qse_env_insertmbs (env, QSE_MT("REQUEST_METHOD"), qse_htre_getqmethodname(req));
qse_env_insertmbs (env, QSE_MT("REQUEST_URI"), qse_htre_getqpath(req));
if (qparam) qse_env_insertmbs (env, QSE_MT("QUERY_STRING"), qparam);
if (qse_env_insertmbs (env, QSE_MT("REQUEST_METHOD"), qse_htre_getqmethodname(req)) <= -1 ||
qse_env_insertmbs (env, QSE_MT("REQUEST_URI"), qse_htre_getqpath(req)) <= -1) goto oops_nomem;
if (qparam && qse_env_insertmbs (env, QSE_MT("QUERY_STRING"), qparam) <= -1) goto oops_nomem;
qse_fmtuintmaxtombs (buf, QSE_COUNTOF(buf), content_length, 10, -1, QSE_MT('\0'), QSE_NULL);
qse_env_insertmbs (env, QSE_MT("CONTENT_LENGTH"), buf);
if (content_type) qse_env_insertmbs (env, QSE_MT("CONTENT_TYPE"), content_type);
if (qse_env_insertmbs (env, QSE_MT("CONTENT_LENGTH"), buf) <= -1) goto oops_nomem;
if (content_type && qse_env_insertmbs (env, QSE_MT("CONTENT_TYPE"), content_type) <= -1) goto oops_nomem;
if (chunked) qse_env_insertmbs (env, QSE_MT("TRANSFER_ENCODING"), QSE_MT("chunked"));
if (chunked && qse_env_insertmbs (env, QSE_MT("TRANSFER_ENCODING"), QSE_MT("chunked")) <= 1) goto oops_nomem;
qse_env_insertmbs (env, "SERVER_SOFTWARE", qse_httpd_getname(httpd));
if (qse_env_insertmbs (env, "SERVER_SOFTWARE", qse_httpd_getname(httpd)) <= -1) goto oops_nomem;
qse_nwadtombs (&client->local_addr, buf, QSE_COUNTOF(buf), QSE_NWADTOMBS_PORT);
qse_env_insertmbs (env, QSE_MT("SERVER_PORT"), buf);
if (qse_env_insertmbs (env, QSE_MT("SERVER_PORT"), buf) <= -1) goto oops_nomem;
qse_nwadtombs (&client->local_addr, buf, QSE_COUNTOF(buf), QSE_NWADTOMBS_ADDR);
qse_env_insertmbs (env, QSE_MT("SERVER_ADDR"), buf);
qse_env_insertmbs (env, QSE_MT("SERVER_NAME"), buf); /* TODO: convert it to a host name */
if (qse_env_insertmbs (env, QSE_MT("SERVER_ADDR"), buf) <= -1) goto oops_nomem;
if (qse_env_insertmbs (env, QSE_MT("SERVER_NAME"), buf) <= -1) goto oops_nomem; /* TODO: convert it to a host name */
qse_nwadtombs (&client->remote_addr, buf, QSE_COUNTOF(buf), QSE_NWADTOMBS_PORT);
qse_env_insertmbs (env, QSE_MT("REMOTE_PORT"), buf);
if (qse_env_insertmbs (env, QSE_MT("REMOTE_PORT"), buf) <= -1) goto oops_nomem;
qse_nwadtombs (&client->remote_addr, buf, QSE_COUNTOF(buf), QSE_NWADTOMBS_ADDR);
qse_env_insertmbs (env, QSE_MT("REMOTE_ADDR"), buf);
if (qse_env_insertmbs (env, QSE_MT("REMOTE_ADDR"), buf) <= -1) goto oops_nomem;
ctx.httpd = httpd;
ctx.env = env;
if (qse_htre_walkheaders (req, cgi_capture_client_header, &ctx) <= -1) return -1;
if (qse_htre_walktrailers (req, cgi_capture_client_header, &ctx) <= -1) return -1;
if (qse_htre_walkheaders (req, cgi_capture_client_header, &ctx) <= -1 ||
qse_htre_walktrailers (req, cgi_capture_client_header, &ctx) <= -1) goto oops;
return 0;
oops_nomem:
httpd->errnum = QSE_HTTPD_ENOMEM;
oops:
return -1;
}
static int cgi_snatch_client_input (

View File

@ -201,6 +201,7 @@ static int proxy_capture_peer_header (qse_htre_t* req, const qse_mchar_t* key, c
{
task_proxy_t* proxy = (task_proxy_t*)ctx;
#if 0
if (!(proxy->httpd->opt.trait & QSE_HTTPD_PROXYNOVIA) && !(proxy->flags & PROXY_VIA_RETURNING))
{
if (qse_mbscasecmp (key, QSE_MT("Via")) == 0)
@ -229,6 +230,7 @@ static int proxy_capture_peer_header (qse_htre_t* req, const qse_mchar_t* key, c
qse_httpd_getname(proxy->httpd));
}
}
#endif
if (qse_mbscasecmp (key, QSE_MT("Connection")) != 0 &&
qse_mbscasecmp (key, QSE_MT("Transfer-Encoding")) != 0)
@ -258,9 +260,9 @@ static int proxy_capture_client_header (qse_htre_t* req, const qse_mchar_t* key,
task_proxy_t* proxy = (task_proxy_t*)ctx;
#if 0
if (!(proxy->flags & (PROXY_TRANSPARENT | PROXY_X_FORWARDED_FOR)))
if (!(proxy->flags & PROXY_TRANSPARENT))
{
if (qse_mbscasecmp (key, QSE_MT("X-Forwarded-For")) == 0)
if (!(proxy->flags & PROXY_X_FORWARDED_FOR) && qse_mbscasecmp (key, QSE_MT("X-Forwarded-For")) == 0)
{
/* append to X-Forwarded-For if it exists in the header.
* note that it add a comma even if the existing value is empty.
@ -274,7 +276,7 @@ static int proxy_capture_client_header (qse_htre_t* req, const qse_mchar_t* key,
return proxy_add_header_to_buffer_with_extra_data (proxy, proxy->reqfwdbuf, key, val, QSE_MT(", %hs"), extra);
}
}
#endif
if (!(proxy->httpd->opt.trait & QSE_HTTPD_PROXYNOVIA) && !(proxy->flags & PROXY_VIA))
{
@ -303,6 +305,7 @@ static int proxy_capture_client_header (qse_htre_t* req, const qse_mchar_t* key,
qse_httpd_getname(proxy->httpd));
}
}
#endif
/* EXPERIMENTAL: REMOVE HEADERS.
* FOR EXAMPLE, You can remove Referer or forge it to give analysis systems harder time */
@ -1145,6 +1148,9 @@ qse_mbs_ncat (proxy->reqfwdbuf, spc, QSE_COUNTOF(spc));
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("X-Forwarded-Proto: ")) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->reqfwdbuf, ((client->status & QSE_HTTPD_CLIENT_SECURE)? QSE_MT("https"): QSE_MT("http"))) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto nomem_oops;
/* TODO: support the Forwarded header in RFC7239.
* Forwarded: for=xxx;by=xxx;prot=xxxx */
}
proxy->resflags |= PROXY_RES_AWAIT_RESHDR;

View File

@ -1,7 +1,7 @@
#include <qse/cmn/env.h>
#include <qse/cmn/mem.h>
#include <qse/cmn/str.h>
#include <qse/cmn/stdio.h>
#include <qse/cmn/sio.h>
#define R(f) \
do { \
@ -106,7 +106,11 @@ static int test3 (void)
env = qse_env_open (QSE_MMGR_GETDFL(), 0, 0);
qse_printf (QSE_T("appending to PATH => %d\n"), qse_env_append (env, QSE_T("xxx"))); /* this should fail as there's no item in the environment */
qse_printf (QSE_T("inserting PATH => %d\n"), qse_env_insert (env, QSE_T("PATH"), QSE_NULL));
qse_printf (QSE_T("appending to PATH => %d\n"), qse_env_append (env, QSE_T(":/usr/xxx/bin:/tmp/bin:/var/lib/qse/bin/sbin/test/bin")));
qse_printf (QSE_T("appending to PATH => %d\n"), qse_env_append (env, QSE_T("")));
qse_printf (QSE_T("inserting HOME => %d\n"), qse_env_insertmbs (env, QSE_MT("HOME"), QSE_NULL));
qse_printf (QSE_T("inserting USER => %d\n"), qse_env_insertwcs (env, QSE_WT("USER"), QSE_NULL));
qse_printf (QSE_T("inserting WHAT => %d\n"), qse_env_insert (env, QSE_T("WHAT"), QSE_NULL));
@ -120,8 +124,12 @@ static int test3 (void)
}
int main ()
{
qse_openstdsios();
R (test1);
R (test2);
R (test3);
qse_closestdsios();
return 0;
}