From bd64702fd4116fc8e612c44c274b8a04d63f1ab5 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sat, 11 Oct 2014 14:33:26 +0000 Subject: [PATCH] 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 --- qse/include/qse/cmn/env.h | 16 +++++ qse/lib/cmn/env.c | 137 ++++++++++++++++++++++++++++++++----- qse/lib/http/httpd-cgi.c | 75 ++++++++++++-------- qse/lib/http/httpd-proxy.c | 12 +++- qse/samples/cmn/env01.c | 10 ++- 5 files changed, 200 insertions(+), 50 deletions(-) diff --git a/qse/include/qse/cmn/env.h b/qse/include/qse/cmn/env.h index 5e069744..b9ab06d9 100644 --- a/qse/include/qse/cmn/env.h +++ b/qse/include/qse/cmn/env.h @@ -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 diff --git a/qse/lib/cmn/env.c b/qse/lib/cmn/env.c index 91a6fe24..cb8ecd7c 100644 --- a/qse/lib/cmn/env.c +++ b/qse/lib/cmn/env.c @@ -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) diff --git a/qse/lib/http/httpd-cgi.c b/qse/lib/http/httpd-cgi.c index d19f8f63..aca84e5d 100644 --- a/qse/lib/http/httpd-cgi.c +++ b/qse/lib/http/httpd-cgi.c @@ -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 ( diff --git a/qse/lib/http/httpd-proxy.c b/qse/lib/http/httpd-proxy.c index cf660382..016c072a 100644 --- a/qse/lib/http/httpd-proxy.c +++ b/qse/lib/http/httpd-proxy.c @@ -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; diff --git a/qse/samples/cmn/env01.c b/qse/samples/cmn/env01.c index 7ca905b3..020d6211 100644 --- a/qse/samples/cmn/env01.c +++ b/qse/samples/cmn/env01.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #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; }