From 2fa6802c03fdc26ae08cbd2ea42f0e5b4c134163 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Mon, 11 Aug 2014 05:44:03 +0000 Subject: [PATCH] enhanced httpd --- qse/cmd/http/httpd.c | 359 +++++++++++++++++++++++++++----- qse/cmd/http/httpd.conf | 31 ++- qse/include/qse/http/htre.h | 8 +- qse/include/qse/http/httpd.h | 4 +- qse/include/qse/http/stdhttpd.h | 67 ++++-- qse/lib/http/httpd-cgi.c | 20 +- qse/lib/http/httpd-dir.c | 4 +- qse/lib/http/httpd-file.c | 4 +- qse/lib/http/httpd-proxy.c | 2 +- qse/lib/http/httpd-std.c | 112 ++++++---- qse/lib/http/httpd-task.c | 4 +- 11 files changed, 481 insertions(+), 134 deletions(-) diff --git a/qse/cmd/http/httpd.c b/qse/cmd/http/httpd.c index 2c230cb1..6ff91b25 100644 --- a/qse/cmd/http/httpd.c +++ b/qse/cmd/http/httpd.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -150,6 +151,7 @@ struct loccfg_t qse_mcstr_t locname; qse_mchar_t* xcfg[XCFG_MAX]; + int root_is_nwad; qse_nwad_t root_nwad; struct @@ -182,6 +184,14 @@ struct loccfg_t struct access_t* tail; } access[2][ACCESS_MAX]; + struct + { + int allow_http: 1; + int allow_connect: 1; + qse_nwad_t dns_nwad; /* TODO: multiple dns */ + qse_nwad_t urs_nwad; /* TODO: multiple urs */ + } proxy; + loccfg_t* next; }; @@ -351,8 +361,8 @@ static int make_resource ( /* TODO: implement a better check that the * destination is not one of the local addresses */ - rsrc->type = QSE_HTTPD_RSRC_ERR; - rsrc->u.err.code = 500; + rsrc->type = QSE_HTTPD_RSRC_ERROR; + rsrc->u.error.code = 500; } else { @@ -376,8 +386,8 @@ static int make_resource ( { /* prohibit no directory listing */ server_xtn->orgfreersrc (httpd, client, req, rsrc); - rsrc->type = QSE_HTTPD_RSRC_ERR; - rsrc->u.err.code = 403; + rsrc->type = QSE_HTTPD_RSRC_ERROR; + rsrc->u.error.code = 403; } return 0; } @@ -417,14 +427,14 @@ static loccfg_t* find_loccfg ( /* the location names are inspected in the order as shown * in the configuration. */ + for (loccfg = hostcfg->loccfg; loccfg; loccfg = loccfg->next) { QSE_ASSERT (loccfg->locname.len > 0); - - if (qse_mbsbeg (qpath, loccfg->locname.ptr) && + if (qse_mbsbeg (qpath, loccfg->locname.ptr) && (loccfg->locname.ptr[loccfg->locname.len - 1] == QSE_MT('/') || - qpath[loccfg->locname.len] == QSE_MT('/') || - qpath[loccfg->locname.len] == QSE_MT('\0'))) + qpath[loccfg->locname.len] == QSE_MT('/') || + qpath[loccfg->locname.len] == QSE_MT('\0'))) { return loccfg; } @@ -434,11 +444,119 @@ static loccfg_t* find_loccfg ( return QSE_NULL; } +static int get_server_root ( + qse_httpd_t* httpd, + qse_httpd_server_t* server, + loccfg_t* loccfg, + const qse_httpd_serverstd_query_info_t* qinfo, + qse_httpd_serverstd_root_t* root) +{ + qse_http_method_t mth; + qse_mchar_t* qpath; + + qse_memset (root, 0, QSE_SIZEOF(*root)); + mth = qse_htre_getqmethodtype (qinfo->req); + qpath = qse_htre_getqpath(qinfo->req); + + qse_memset (root, 0, QSE_SIZEOF(*root)); + if (mth == QSE_HTTP_CONNECT) + { + if (loccfg->proxy.allow_connect) + { + /* TODO: check on what conditions CONNECT is allowed. */ + /* TODO: disallow connecting back to self */ + /* TODO: Proxy-Authorization???? */ + + root->type = QSE_HTTPD_SERVERSTD_ROOT_PROXY; + root->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_RAW; + + if (qse_mbstonwad(qpath, &root->u.proxy.dst.nwad) <= -1) + { + root->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_DST_STR; + root->u.proxy.dst.str = qpath; + } + else + { + /* make the source binding type the same as destination */ + /* no default port for raw proxying */ + root->u.proxy.src.nwad.type = root->u.proxy.dst.nwad.type; + } + return 0; + } + else + { + root->type = QSE_HTTPD_SERVERSTD_ROOT_ERROR; + root->u.error.code = 403; /* forbidden */ + return 0; + } + } + + if (loccfg->proxy.allow_http) + { + if (qse_mbszcasecmp (qpath, QSE_MT("http://"), 7) == 0) + { + qse_mchar_t* host, * slash; + + host = qpath + 7; + slash = qse_mbschr (host, QSE_MT('/')); + + if (slash && slash - host > 0) + { + /* TODO: refrain from manipulating the request like this */ + + root->type = QSE_HTTPD_SERVERSTD_ROOT_PROXY; + + qse_memmove (host - 1, host, slash - host); + slash[-1] = QSE_MT('\0'); + host = host - 1; + root->u.proxy.host = host; + + if (qse_mbstonwad (host, &root->u.proxy.dst.nwad) <= -1) + { + root->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_DST_STR; + root->u.proxy.dst.str = host; + } + else + { + /* make the source binding type the same as destination */ + if (qse_getnwadport(&root->u.proxy.dst.nwad) == 0) + qse_setnwadport (&root->u.proxy.dst.nwad, qse_hton16(80)); + root->u.proxy.src.nwad.type = root->u.proxy.dst.nwad.type; + } + + /* TODO: refrain from manipulating the request like this */ + qinfo->req->u.q.path = slash; /* TODO: use setqpath or something... */ + + return 0; + } + } + else + { + root->type = QSE_HTTPD_SERVERSTD_ROOT_ERROR; + root->u.error.code = 403; /* forbidden */ + return 0; + } + } + + if (loccfg->root_is_nwad) + { + root->type = QSE_HTTPD_SERVERSTD_ROOT_NWAD; + root->u.nwad = loccfg->root_nwad; + } + else + { + root->type = QSE_HTTPD_SERVERSTD_ROOT_PATH; + root->u.path.val = loccfg->xcfg[XCFG_ROOT]; + root->u.path.rpl = loccfg->locname.len; + } + + return 0; +} static int query_server ( qse_httpd_t* httpd, qse_httpd_server_t* server, - qse_htre_t* req, const qse_mchar_t* xpath, - qse_httpd_serverstd_query_code_t code, void* result) + qse_httpd_serverstd_query_code_t code, + qse_httpd_serverstd_query_info_t* qinfo, void* result) { httpd_xtn_t* httpd_xtn; server_xtn_t* server_xtn; @@ -460,42 +578,87 @@ static int query_server ( if (server_xtn->cfgtab) { - if (req && server_xtn->cfgtab) + if (qinfo && qinfo->req && server_xtn->cfgtab) { - const qse_htre_hdrval_t* hosthdr; - const qse_mchar_t* host; + const qse_mchar_t* host = QSE_NULL; const qse_mchar_t* qpath; + qse_http_method_t mth; - qpath = qse_htre_getqpath (req); + mth = qse_htre_getqmethodtype (qinfo->req); + qpath = qse_htre_getqpath (qinfo->req); + if (mth == QSE_HTTP_CONNECT) + { + /* the query path for CONNECT is not a path name, but + * a host name. the path is adjusted to the root directory. */ + host = qpath; + qpath = QSE_MT("/"); + } + else + { + const qse_htre_hdrval_t* hosthdr; - hosthdr = qse_htre_getheaderval (req, QSE_MT("Host")); - if (hosthdr) + hosthdr = qse_htre_getheaderval (qinfo->req, QSE_MT("Host")); + if (hosthdr) + { + /*while (hosthdr->next) hosthdr = hosthdr->next; */ + host = hosthdr->ptr; + } + } + + if (host) { const qse_mchar_t* colon; qse_size_t hostlen; - /*while (hosthdr->next) hosthdr = hosthdr->next; */ - host = hosthdr->ptr; - /* remove :port-number if the host name contains it */ colon = qse_mbsrchr(host, QSE_MT(':')); if (colon) hostlen = colon - host; else hostlen = qse_mbslen(host); - loccfg = find_loccfg (httpd, server_xtn->cfgtab, host, hostlen, qpath); + /* Wild card search + * + * www.tango.com => + * www.tango.com + * tango.com + * com <-- up to here + * * + * + * tango.com => + * tango.com + * com <-- up to here + * * + */ + while (hostlen > 0) + { + qse_mchar_t c; + + loccfg = find_loccfg (httpd, server_xtn->cfgtab, host, hostlen, qpath); + if (loccfg) goto found; + + /* skip the current segment */ + do + { + c = *host++; + hostlen--; + } + while (c != QSE_MT('.') && hostlen > 0); + } + } + if (loccfg == QSE_NULL) loccfg = find_loccfg (httpd, server_xtn->cfgtab, QSE_MT("*"), 1, qpath); } + if (loccfg == QSE_NULL) loccfg = find_loccfg (httpd, server_xtn->cfgtab, QSE_MT("*"), 1, QSE_MT("/")); } if (loccfg == QSE_NULL) loccfg = &httpd_xtn->dflcfg; +found: switch (code) { - case QSE_HTTPD_SERVERSTD_ROOT: #if 0 - if (qse_mbscmp (qse_htre_getqpath(req), QSE_MT("/version")) == 0) + if (qse_mbscmp (qse_htre_getqpath(qinfo->req), QSE_MT("/version")) == 0) { /* return static text without inspecting further */ ((qse_httpd_serverstd_root_t*)result)->type = QSE_HTTPD_SERVERSTD_ROOT_TEXT; @@ -505,6 +668,8 @@ static int query_server ( else #endif + return get_server_root (httpd, server, loccfg, qinfo, result); +/* if (loccfg->root_is_nwad) { ((qse_httpd_serverstd_root_t*)result)->type = QSE_HTTPD_SERVERSTD_ROOT_NWAD; @@ -516,7 +681,7 @@ static int query_server ( ((qse_httpd_serverstd_root_t*)result)->u.path.val = loccfg->xcfg[XCFG_ROOT]; ((qse_httpd_serverstd_root_t*)result)->u.path.rpl = loccfg->locname.len; } - return 0; + return 0;*/ case QSE_HTTPD_SERVERSTD_REALM: { @@ -525,7 +690,7 @@ static int query_server ( ((qse_httpd_serverstd_realm_t*)result)->name = loccfg->xcfg[XCFG_REALM]; - apath = xpath? xpath: qse_htre_getqpath (req); + apath = qinfo->xpath? qinfo->xpath: qse_htre_getqpath (qinfo->req); if (apath) { const qse_mchar_t* base; @@ -609,7 +774,7 @@ static int query_server ( qse_httpd_serverstd_cgi_t* scgi; const qse_mchar_t* xpath_base; - xpath_base = qse_mbsbasename (xpath); + xpath_base = qse_mbsbasename (qinfo->xpath); scgi = (qse_httpd_serverstd_cgi_t*)result; qse_memset (scgi, 0, QSE_SIZEOF(*scgi)); @@ -639,7 +804,7 @@ static int query_server ( qse_size_t i; const qse_mchar_t* xpath_base; - xpath_base = qse_mbsbasename (xpath); + xpath_base = qse_mbsbasename (qinfo->xpath); *(const qse_mchar_t**)result = QSE_NULL; for (i = 0; i < QSE_COUNTOF(loccfg->mime); i++) @@ -663,7 +828,7 @@ static int query_server ( case QSE_HTTPD_SERVERSTD_DIRACC: case QSE_HTTPD_SERVERSTD_FILEACC: { - switch (qse_htre_getqmethodtype(req)) + switch (qse_htre_getqmethodtype(qinfo->req)) { case QSE_HTTP_OPTIONS: case QSE_HTTP_HEAD: @@ -678,7 +843,7 @@ static int query_server ( id = (code == QSE_HTTPD_SERVERSTD_DIRACC)? 0: 1; - xpath_base = qse_mbsbasename (xpath); + xpath_base = qse_mbsbasename (qinfo->xpath); *(int*)result = 200; for (i = 0; i < QSE_COUNTOF(loccfg->access[id]); i++) @@ -708,7 +873,7 @@ static int query_server ( } } - return server_xtn->orgquery (httpd, server, req, xpath, code, result); + return server_xtn->orgquery (httpd, server, code, qinfo, result); } /* --------------------------------------------------------------------- */ @@ -739,11 +904,12 @@ static struct { QSE_T("pseudonym"), QSE_T("server-default.pseudonym") } }; +/* local access items */ static struct { const qse_char_t* x; const qse_char_t* y; -} loc_acc_items[] = +} loc_acc_items[] = { { QSE_T("dir-access"), QSE_T("server-default.dir-access") }, { QSE_T("file-access"), QSE_T("server-default.file-access") } @@ -841,19 +1007,86 @@ static void free_loccfg_contents (qse_httpd_t* httpd, loccfg_t* loccfg) if (loccfg->locname.ptr) qse_httpd_freemem (httpd, loccfg->locname.ptr); } -static int load_loccfg (qse_httpd_t* httpd, qse_xli_list_t* list, loccfg_t* cfg) +static int get_boolean (const qse_xli_str_t* v) +{ + return (qse_strxcasecmp (v->ptr, v->len, QSE_T("yes")) == 0 || + qse_strxcasecmp (v->ptr, v->len, QSE_T("on")) == 0); +} + +static int load_loccfg_proxy (qse_httpd_t* httpd, qse_xli_t* xli, qse_xli_list_t* list, loccfg_t* cfg) +{ + qse_xli_pair_t* pair; + qse_xli_list_t* proxy = QSE_NULL; + qse_xli_list_t* default_proxy = QSE_NULL; + /*qse_xli_atom_t* atom;*/ + + pair = qse_xli_findpair (xli, list, QSE_T("proxy")); + if (pair) + { + QSE_ASSERT (pair->val->type == QSE_XLI_LIST); + proxy = (qse_xli_list_t*)pair->val; + } + + pair = qse_xli_findpair (xli, QSE_NULL, QSE_T("server-default.proxy")); + if (pair) + { + QSE_ASSERT (pair->val->type == QSE_XLI_LIST); + default_proxy = (qse_xli_list_t*)pair->val; + } + + + pair = QSE_NULL; + if (proxy) pair = qse_xli_findpair (xli, proxy, QSE_T("http")); /* server.host[].location[].proxy.http */ + if (!pair && default_proxy) pair = qse_xli_findpair (xli, default_proxy, QSE_T("http")); /* server-default.proxy.http */ + if (pair) cfg->proxy.allow_http = get_boolean ((qse_xli_str_t*)pair->val); + + pair = QSE_NULL; + if (proxy) pair = qse_xli_findpair (xli, proxy, QSE_T("connect")); + if (!pair && default_proxy) pair = qse_xli_findpair (xli, default_proxy, QSE_T("connect")); + if (pair) cfg->proxy.allow_connect = get_boolean ((qse_xli_str_t*)pair->val); + + pair = QSE_NULL; + if (proxy) pair = qse_xli_findpair (xli, proxy, QSE_T("dns-server")); + if (!pair && default_proxy) pair = qse_xli_findpair (xli, default_proxy, QSE_T("dns-server")); + if (pair) + { + qse_xli_str_t* str = (qse_xli_str_t*)pair->val; + if (qse_strtonwad (str->ptr, &cfg->proxy.dns_nwad) <= -1) + { + qse_printf (QSE_T("ERROR: invalid address for proxy dns - %s"), str->ptr); + return -1; + } + } + + pair = QSE_NULL; + if (proxy) pair = qse_xli_findpair (xli, proxy, QSE_T("urs-server")); + if (!pair && default_proxy) pair = qse_xli_findpair (xli, default_proxy, QSE_T("urs-server")); + if (pair) + { + qse_xli_str_t* str = (qse_xli_str_t*)pair->val; + if (qse_strtonwad (str->ptr, &cfg->proxy.urs_nwad) <= -1) + { + qse_printf (QSE_T("ERROR: invalid address for proxy urs - %s"), str->ptr); + return -1; + } + } + + return 0; +} + +static int load_loccfg (qse_httpd_t* httpd, qse_xli_t* xli, qse_xli_list_t* list, loccfg_t* cfg) { qse_size_t i; qse_xli_pair_t* pair; qse_xli_atom_t* atom; - httpd_xtn_t* httpd_xtn; + /*httpd_xtn_t* httpd_xtn; - httpd_xtn = qse_httpd_getxtnstd (httpd); + httpd_xtn = qse_httpd_getxtnstd (httpd);*/ for (i = 0; i < QSE_COUNTOF(loc_xcfg_items); i++) { - pair = qse_xli_findpair (httpd_xtn->xli, list, loc_xcfg_items[i].x); - if (!pair) pair = qse_xli_findpair (httpd_xtn->xli, QSE_NULL, loc_xcfg_items[i].y); + pair = qse_xli_findpair (xli, list, loc_xcfg_items[i].x); + if (!pair) pair = qse_xli_findpair (xli, QSE_NULL, loc_xcfg_items[i].y); if (pair && pair->val->type == QSE_XLI_STR) { cfg->xcfg[i] = qse_httpd_strntombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr, ((qse_xli_str_t*)pair->val)->len); @@ -866,14 +1099,14 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_list_t* list, loccfg_t* cfg) } } - pair = qse_xli_findpair (httpd_xtn->xli, list, QSE_T("index")); - if (!pair) pair = qse_xli_findpair (httpd_xtn->xli, QSE_NULL, QSE_T("server-default.index")); + pair = qse_xli_findpair (xli, list, QSE_T("index")); + if (!pair) pair = qse_xli_findpair (xli, QSE_NULL, QSE_T("server-default.index")); if (pair && pair->val->type == QSE_XLI_STR) { qse_char_t* duptmp; qse_size_t count, duplen; - duptmp = qse_xli_dupflatstr (httpd_xtn->xli, (qse_xli_str_t*)pair->val, &duplen, &count); + duptmp = qse_xli_dupflatstr (xli, (qse_xli_str_t*)pair->val, &duplen, &count); if (duptmp == QSE_NULL) { qse_printf (QSE_T("ERROR: memory failure in copying index\n")); @@ -881,7 +1114,7 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_list_t* list, loccfg_t* cfg) } cfg->index.files = qse_httpd_strntombsdup (httpd, duptmp, duplen); - qse_xli_freemem (httpd_xtn->xli, duptmp); + qse_xli_freemem (xli, duptmp); if (cfg->index.files == QSE_NULL) { @@ -892,8 +1125,8 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_list_t* list, loccfg_t* cfg) cfg->index.count = count; } - pair = qse_xli_findpair (httpd_xtn->xli, list, QSE_T("cgi")); - if (!pair) pair = qse_xli_findpair (httpd_xtn->xli, QSE_NULL, QSE_T("server-default.cgi")); + pair = qse_xli_findpair (xli, list, QSE_T("cgi")); + if (!pair) pair = qse_xli_findpair (xli, QSE_NULL, QSE_T("server-default.cgi")); if (pair && pair->val->type == QSE_XLI_LIST) { qse_xli_list_t* cgilist = (qse_xli_list_t*)pair->val; @@ -965,8 +1198,8 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_list_t* list, loccfg_t* cfg) } } - pair = qse_xli_findpair (httpd_xtn->xli, list, QSE_T("auth-rule")); - if (!pair) pair = qse_xli_findpair (httpd_xtn->xli, QSE_NULL, QSE_T("server-default.auth-rule")); + pair = qse_xli_findpair (xli, list, QSE_T("auth-rule")); + if (!pair) pair = qse_xli_findpair (xli, QSE_NULL, QSE_T("server-default.auth-rule")); if (pair && pair->val->type == QSE_XLI_LIST) { qse_xli_list_t* auth_rule_list = (qse_xli_list_t*)pair->val; @@ -1015,8 +1248,8 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_list_t* list, loccfg_t* cfg) } } - pair = qse_xli_findpair (httpd_xtn->xli, list, QSE_T("mime")); - if (!pair) pair = qse_xli_findpair (httpd_xtn->xli, QSE_NULL, QSE_T("server-default.mime")); + pair = qse_xli_findpair (xli, list, QSE_T("mime")); + if (!pair) pair = qse_xli_findpair (xli, QSE_NULL, QSE_T("server-default.mime")); if (pair && pair->val->type == QSE_XLI_LIST) { qse_xli_list_t* mimelist = (qse_xli_list_t*)pair->val; @@ -1070,8 +1303,8 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_list_t* list, loccfg_t* cfg) for (i = 0; i < 2; i++) { - pair = qse_xli_findpair (httpd_xtn->xli, list, loc_acc_items[i].x); - if (!pair) pair = qse_xli_findpair (httpd_xtn->xli, QSE_NULL, loc_acc_items[i].y); + pair = qse_xli_findpair (xli, list, loc_acc_items[i].x); + if (!pair) pair = qse_xli_findpair (xli, QSE_NULL, loc_acc_items[i].y); if (pair && pair->val->type == QSE_XLI_LIST) { qse_xli_list_t* acclist = (qse_xli_list_t*)pair->val; @@ -1129,8 +1362,11 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_list_t* list, loccfg_t* cfg) } } + if (load_loccfg_proxy (httpd, xli, list, cfg) <= -1) return -1; + /* TODO: support multiple auth entries here and above */ + #if 0 /* TODO: perform more sanity check */ if (qse_mbschr (cfg->xcfg[XCFG_AUTH], QSE_MT(':')) == QSE_NULL) @@ -1155,7 +1391,7 @@ static void free_server_hostcfg (qse_httpd_t* httpd, server_hostcfg_t* hostcfg) while (lc) { cur = lc; - lc = lc->next; + lc = lc->next; free_loccfg_contents (httpd, cur); qse_httpd_freemem (httpd, cur); @@ -1272,7 +1508,7 @@ static int load_server_config (qse_httpd_t* httpd, qse_httpd_server_t* server, q hostcfg->loccfg = loccfg; /* load the data now */ - if (load_loccfg (httpd, (qse_xli_list_t*)loc->val, loccfg) <= -1) goto oops; + if (load_loccfg (httpd, httpd_xtn->xli, (qse_xli_list_t*)loc->val, loccfg) <= -1) goto oops; /* clone the location name */ loccfg->locname.ptr = qse_httpd_strtombsdup (httpd, @@ -1432,6 +1668,16 @@ static int open_config_file (qse_httpd_t* httpd) { QSE_T("server-default.error-head"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, { QSE_T("server-default.error-foot"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, { QSE_T("server-default.pseudonym"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server-default.proxy"), { QSE_XLI_SCM_VALLIST | QSE_XLI_SCM_KEYNODUP, 0, 0 } }, + { QSE_T("server-default.proxy.http"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server-default.proxy.connect"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server-default.proxy.pseudonym"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server-default.proxy.dns-server"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server-default.proxy.dns-timeout"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server-default.proxy.dns-retries"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server-default.proxy.urs-server"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server-default.proxy.urs-timeout"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server-default.proxy.urs-retries"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, { QSE_T("server"), { QSE_XLI_SCM_VALLIST, 0, 0 } }, { QSE_T("server.bind"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, @@ -1472,7 +1718,18 @@ static int open_config_file (qse_httpd_t* httpd) { QSE_T("server.host.location.dir-foot"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, { QSE_T("server.host.location.error-head"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, { QSE_T("server.host.location.error-foot"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, - { QSE_T("server.host.location.pseudonym"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } } + { QSE_T("server.host.location.pseudonym"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + + { QSE_T("server.host.location.proxy"), { QSE_XLI_SCM_VALLIST | QSE_XLI_SCM_KEYNODUP, 0, 0 } }, + { QSE_T("server.host.location.proxy.http"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server.host.location.proxy.connect"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server.host.location.proxy.pseudonym"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server.host.location.proxy.dns-server"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server.host.location.proxy.dns-timeout"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server.host.location.proxy.dns-retries"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server.host.location.proxy.urs-server"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server.host.location.proxy.urs-timeout"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, + { QSE_T("server.host.location.proxy.urs-retries"), { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 } }, }; @@ -1645,7 +1902,7 @@ static int load_config (qse_httpd_t* httpd) pair = qse_xli_findpair (httpd_xtn->xli, QSE_NULL, QSE_T("server-default")); if (pair && pair->val->type == QSE_XLI_LIST) { - if (load_loccfg (httpd, (qse_xli_list_t*)pair->val, &httpd_xtn->dflcfg) <= -1) + if (load_loccfg (httpd, httpd_xtn->xli, (qse_xli_list_t*)pair->val, &httpd_xtn->dflcfg) <= -1) { qse_fprintf (QSE_STDERR, QSE_T("failed to load configuration from %s\n"), httpd_xtn->cfgfile); goto oops; diff --git a/qse/cmd/http/httpd.conf b/qse/cmd/http/httpd.conf index 230b8099..de65a21b 100644 --- a/qse/cmd/http/httpd.conf +++ b/qse/cmd/http/httpd.conf @@ -39,6 +39,7 @@ server-default { #} cgi { + #name "t3.nph" = "nph"; #prefix "t3." = "nph"; suffix ".cgi"; @@ -53,6 +54,27 @@ server-default { @include "httpd-mime.conf"; } + + + #################################################################### + # + # Accee control including dir-access and file-access can be + # defined using patterns and actions shown below + # + # Pattern + # prefix ".xxxx" (prefix match) + # suffix "xxxx." (suffix match) + # name "xxxx.yyyy" (exact match) + # other (all others) + # + # Action + # noent + # forbid + # ok + # + #################################################################### + + #################################################################### # control access to directories #################################################################### @@ -100,6 +122,14 @@ server-default { # override it with error-foot. #################################################################### #error-foot = "QSEHTTPD v1"; + + #################################################################### + # Default proxy configuration + #################################################################### + proxy { + http = yes; + connect = yes; + } } server { @@ -155,7 +185,6 @@ server { } - # virtual hosts are not supported yet. #host "www.google.com" { # location "/" { # root = "/home/www/google"; diff --git a/qse/include/qse/http/htre.h b/qse/include/qse/http/htre.h index 04f45a58..448e9bea 100644 --- a/qse/include/qse/http/htre.h +++ b/qse/include/qse/http/htre.h @@ -78,17 +78,17 @@ struct qse_htre_t qse_http_method_t type; const qse_mchar_t* name; } method; - const qse_mchar_t* path; - const qse_mchar_t* param; + qse_mchar_t* path; + qse_mchar_t* param; } q; struct { struct { int val; - const qse_mchar_t* str; + qse_mchar_t* str; } code; - const qse_mchar_t* mesg; + qse_mchar_t* mesg; } s; } u; diff --git a/qse/include/qse/http/httpd.h b/qse/include/qse/http/httpd.h index 8030ce14..cd2c9d83 100644 --- a/qse/include/qse/http/httpd.h +++ b/qse/include/qse/http/httpd.h @@ -528,7 +528,7 @@ enum qse_httpd_rsrc_type_t QSE_HTTPD_RSRC_AUTH, QSE_HTTPD_RSRC_CGI, QSE_HTTPD_RSRC_DIR, - QSE_HTTPD_RSRC_ERR, + QSE_HTTPD_RSRC_ERROR, QSE_HTTPD_RSRC_FILE, QSE_HTTPD_RSRC_PROXY, QSE_HTTPD_RSRC_RELOC, @@ -606,7 +606,7 @@ struct qse_httpd_rsrc_t struct { int code; - } err; + } error; struct { diff --git a/qse/include/qse/http/stdhttpd.h b/qse/include/qse/http/stdhttpd.h index 10892ee4..2900f4d6 100644 --- a/qse/include/qse/http/stdhttpd.h +++ b/qse/include/qse/http/stdhttpd.h @@ -41,7 +41,9 @@ enum qse_httpd_serverstd_root_type_t { QSE_HTTPD_SERVERSTD_ROOT_PATH, QSE_HTTPD_SERVERSTD_ROOT_NWAD, - QSE_HTTPD_SERVERSTD_ROOT_TEXT + QSE_HTTPD_SERVERSTD_ROOT_TEXT, + QSE_HTTPD_SERVERSTD_ROOT_PROXY, + QSE_HTTPD_SERVERSTD_ROOT_ERROR }; typedef enum qse_httpd_serverstd_root_type_t qse_httpd_serverstd_root_type_t; @@ -56,12 +58,21 @@ struct qse_httpd_serverstd_root_t const qse_mchar_t* val; qse_size_t rpl; /* replacement length */ } path; + qse_nwad_t nwad; + struct { const qse_mchar_t* ptr; const qse_mchar_t* mime; } text; + + struct qse_httpd_rsrc_proxy_t proxy; + + struct + { + int code; /* http error code */ + } error; } u; }; @@ -101,37 +112,51 @@ struct qse_httpd_serverstd_ssl_t const qse_mchar_t* keyfile; }; +typedef struct qse_httpd_serverstd_proxy_t qse_httpd_serverstd_proxy_t; +struct qse_httpd_serverstd_proxy_t +{ + int tproxy: 1; + const qse_mchar_t* pseudonym; +}; + enum qse_httpd_serverstd_query_code_t { - QSE_HTTPD_SERVERSTD_SSL, /* qse_httpd_serverstd_ssl_t */ + QSE_HTTPD_SERVERSTD_SSL, /* qse_httpd_serverstd_ssl_t */ - QSE_HTTPD_SERVERSTD_ROOT, /* qse_httpd_serverstd_root_t */ - QSE_HTTPD_SERVERSTD_REALM, /* qse_httpd_serverstd_realm_t */ - QSE_HTTPD_SERVERSTD_AUTH, /* qse_httpd_serverstd_auth_t */ - QSE_HTTPD_SERVERSTD_ERRHEAD, /* const qse_mchar_t* */ - QSE_HTTPD_SERVERSTD_ERRFOOT, /* const qse_mchar_t* */ + QSE_HTTPD_SERVERSTD_ROOT, /* qse_httpd_serverstd_root_t */ + QSE_HTTPD_SERVERSTD_REALM, /* qse_httpd_serverstd_realm_t */ + QSE_HTTPD_SERVERSTD_AUTH, /* qse_httpd_serverstd_auth_t */ + QSE_HTTPD_SERVERSTD_ERRHEAD, /* const qse_mchar_t* */ + QSE_HTTPD_SERVERSTD_ERRFOOT, /* const qse_mchar_t* */ - QSE_HTTPD_SERVERSTD_DIRHEAD, /* const qse_mchar_t* */ - QSE_HTTPD_SERVERSTD_DIRFOOT, /* const qse_mchar_t* */ + QSE_HTTPD_SERVERSTD_DIRHEAD, /* const qse_mchar_t* */ + QSE_HTTPD_SERVERSTD_DIRFOOT, /* const qse_mchar_t* */ - QSE_HTTPD_SERVERSTD_PSEUDONYM, /* const qse_mchar_t*, pseudonym to use in Via: */ + QSE_HTTPD_SERVERSTD_PSEUDONYM, /* const qse_mchar_t*, pseudonym to use in Via: */ - QSE_HTTPD_SERVERSTD_INDEX, /* qse_httpd_serverstd_index_t */ - QSE_HTTPD_SERVERSTD_CGI, /* qse_httpd_serverstd_cgi_t */ - QSE_HTTPD_SERVERSTD_MIME, /* const qse_mchar_t* */ - QSE_HTTPD_SERVERSTD_DIRACC, /* int (http error code) */ - QSE_HTTPD_SERVERSTD_FILEACC /* int (http error code) */ + QSE_HTTPD_SERVERSTD_INDEX, /* qse_httpd_serverstd_index_t */ + QSE_HTTPD_SERVERSTD_CGI, /* qse_httpd_serverstd_cgi_t */ + QSE_HTTPD_SERVERSTD_MIME, /* const qse_mchar_t* */ + QSE_HTTPD_SERVERSTD_DIRACC, /* int (http error code) */ + QSE_HTTPD_SERVERSTD_FILEACC /* int (http error code) */ }; typedef enum qse_httpd_serverstd_query_code_t qse_httpd_serverstd_query_code_t; +struct qse_httpd_serverstd_query_info_t +{ + qse_htre_t* req; + qse_mchar_t* xpath; /* query path combined with document root */ +}; +typedef struct qse_httpd_serverstd_query_info_t qse_httpd_serverstd_query_info_t; + + typedef int (*qse_httpd_serverstd_query_t) ( - qse_httpd_t* httpd, - qse_httpd_server_t* server, - qse_htre_t* req, - const qse_mchar_t* xpath, - qse_httpd_serverstd_query_code_t code, - void* result + qse_httpd_t* httpd, + qse_httpd_server_t* server, + qse_httpd_serverstd_query_code_t code, + const qse_httpd_serverstd_query_info_t* info, + void* result ); enum qse_httpd_serverstd_opt_t diff --git a/qse/lib/http/httpd-cgi.c b/qse/lib/http/httpd-cgi.c index fb8042bd..11c497fa 100644 --- a/qse/lib/http/httpd-cgi.c +++ b/qse/lib/http/httpd-cgi.c @@ -58,11 +58,11 @@ struct task_cgi_t int init_failed; qse_httpd_t* httpd; - const qse_mchar_t* path; - const qse_mchar_t* script; - const qse_mchar_t* suffix; - const qse_mchar_t* root; - const qse_mchar_t* shebang; + qse_mchar_t* path; + qse_mchar_t* script; + qse_mchar_t* suffix; + qse_mchar_t* root; + qse_mchar_t* shebang; int method; qse_http_version_t version; @@ -1601,16 +1601,16 @@ qse_httpd_task_t* qse_httpd_entaskcgi ( if (rsrc.root == QSE_NULL) rsrc.root = QSE_MT(""); if (rsrc.shebang == QSE_NULL) rsrc.shebang = QSE_MT(""); - arg.path.ptr = rsrc.path; + arg.path.ptr = (qse_mchar_t*)rsrc.path; arg.path.len = qse_mbslen(rsrc.path); - arg.script.ptr = rsrc.script; + arg.script.ptr = (qse_mchar_t*)rsrc.script; arg.script.len = qse_mbslen(rsrc.script); - arg.suffix.ptr = rsrc.suffix; + arg.suffix.ptr = (qse_mchar_t*)rsrc.suffix; arg.suffix.len = qse_mbslen(rsrc.suffix); - arg.root.ptr = rsrc.root; + arg.root.ptr = (qse_mchar_t*)rsrc.root; arg.root.len = qse_mbslen(rsrc.root); arg.nph = rsrc.nph; - arg.shebang.ptr = rsrc.shebang; + arg.shebang.ptr = (qse_mchar_t*)rsrc.shebang; arg.shebang.len = qse_mbslen(rsrc.shebang); arg.req = req; diff --git a/qse/lib/http/httpd-dir.c b/qse/lib/http/httpd-dir.c index c67b5c63..0dd9a0ca 100644 --- a/qse/lib/http/httpd-dir.c +++ b/qse/lib/http/httpd-dir.c @@ -606,11 +606,11 @@ qse_httpd_task_t* qse_httpd_entaskdir ( /* create a directory listing task */ qse_httpd_task_t task, * x; - data.path.ptr = dir->path; + data.path.ptr = (qse_mchar_t*)dir->path; data.path.len = qse_mbslen(data.path.ptr); data.qpath.ptr = qse_htre_getqpath(req); data.qpath.len = qse_mbslen(data.qpath.ptr); - data.head.ptr = dir->head? dir->head: QSE_MT(""); + data.head.ptr = dir->head? (qse_mchar_t*)dir->head: QSE_MT(""); data.head.len = qse_mbslen(data.head.ptr); data.foot.ptr = dir->foot? dir->foot: qse_httpd_getname(httpd); data.foot.len = qse_mbslen(data.foot.ptr); diff --git a/qse/lib/http/httpd-file.c b/qse/lib/http/httpd-file.c index d63971ab..d8ff6af3 100644 --- a/qse/lib/http/httpd-file.c +++ b/qse/lib/http/httpd-file.c @@ -539,7 +539,7 @@ qse_httpd_task_t* qse_httpd_entaskfile ( qse_size_t xtnsize; QSE_MEMSET (&data, 0, QSE_SIZEOF(data)); - data.path.ptr = path; + data.path.ptr = (qse_mchar_t*)path; data.path.len = qse_mbslen(path); data.version = *qse_htre_getversion(req); data.keepalive = (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE); @@ -563,7 +563,7 @@ qse_httpd_task_t* qse_httpd_entaskfile ( if (mime) { - data.u.get.mime.ptr = mime; + data.u.get.mime.ptr = (qse_mchar_t*)mime; data.u.get.mime.len = qse_mbslen(mime); xtnsize += data.u.get.mime.len + 1; } diff --git a/qse/lib/http/httpd-proxy.c b/qse/lib/http/httpd-proxy.c index 359e833d..c2bd3577 100644 --- a/qse/lib/http/httpd-proxy.c +++ b/qse/lib/http/httpd-proxy.c @@ -943,7 +943,7 @@ static int task_init_proxy ( { const qse_mchar_t* qpath; const qse_mchar_t* metnam; - const qse_mchar_t* host_ptr; + const qse_mchar_t* host_ptr = QSE_NULL; qse_mchar_t cliaddrbuf[128]; qse_size_t total_len; diff --git a/qse/lib/http/httpd-std.c b/qse/lib/http/httpd-std.c index 4de9170a..3fb02a68 100644 --- a/qse/lib/http/httpd-std.c +++ b/qse/lib/http/httpd-std.c @@ -554,14 +554,14 @@ static int init_xtn_ssl (qse_httpd_t* httpd, qse_httpd_server_t* server) xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); server_xtn = (server_xtn_t*)qse_httpd_getserverxtn (httpd, server); - if (server_xtn->query (httpd, server, QSE_NULL, QSE_NULL, QSE_HTTPD_SERVERSTD_SSL, &ssl) <= -1) + if (server_xtn->query (httpd, server, QSE_HTTPD_SERVERSTD_SSL, QSE_NULL, &ssl) <= -1) { return -1; } if (ssl.certfile == QSE_NULL || ssl.keyfile == QSE_NULL) { - qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); + qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); return -1; } @@ -2126,7 +2126,7 @@ if (qse_htre_getcontentlen(req) > 0) /* failed to make a resource. just send the internal server error. * the makersrc handler can return a negative number to return * '500 Internal Server Error'. If it wants to return a specific - * error code, it should return 0 with the QSE_HTTPD_RSRC_ERR + * error code, it should return 0 with the QSE_HTTPD_RSRC_ERROR * resource. */ qse_httpd_discardcontent (httpd, req); task = qse_httpd_entaskerr (httpd, client, QSE_NULL, 500, req); @@ -2148,7 +2148,7 @@ if (qse_htre_getcontentlen(req) > 0) /* if the resource is indicating to return an error, * discard the contents since i won't return them */ - if (rsrc.type == QSE_HTTPD_RSRC_ERR) + if (rsrc.type == QSE_HTTPD_RSRC_ERROR) { qse_httpd_discardcontent (httpd, req); } @@ -2175,7 +2175,7 @@ printf ("CANOT MAKE RESOURCE.... %s\n", qse_htre_getqpath(req)); /* failed to make a resource. just send the internal server error. * the makersrc handler can return a negative number to return * '500 Internal Server Error'. If it wants to return a specific - * error code, it should return 0 with the QSE_HTTPD_RSRC_ERR + * error code, it should return 0 with the QSE_HTTPD_RSRC_ERROR * resource. */ task = qse_httpd_entaskerr (httpd, client, QSE_NULL, 500, req); } @@ -2237,10 +2237,10 @@ static int format_error ( server_xtn = qse_httpd_getserverxtn (httpd, client->server); - if (server_xtn->query (httpd, client->server, QSE_NULL, QSE_NULL, QSE_HTTPD_SERVERSTD_ERRHEAD, &head) <= -1) head = QSE_NULL; + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_ERRHEAD, QSE_NULL, &head) <= -1) head = QSE_NULL; if (head == QSE_NULL) head = QSE_MT(""); - if (server_xtn->query (httpd, client->server, QSE_NULL, QSE_NULL, QSE_HTTPD_SERVERSTD_ERRFOOT, &foot) <= -1) foot = QSE_NULL; + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_ERRFOOT, QSE_NULL, &foot) <= -1) foot = QSE_NULL; if (foot == QSE_NULL) foot = qse_httpd_getname(httpd); msg = qse_httpstatustombs(code); @@ -2486,8 +2486,15 @@ static int attempt_cgi ( if (tmp->final_match) { + qse_httpd_serverstd_query_info_t qinfo; + /* it is a final match. tmp->xpath is tmp->root + tmp->qpath */ - if (server_xtn->query (httpd, client->server, req, tmp->xpath, QSE_HTTPD_SERVERSTD_CGI, &cgi) >= 0 && cgi.cgi) + + QSE_MEMSET (&qinfo, 0, QSE_SIZEOF(qinfo)); + qinfo.req = req; + qinfo.xpath = tmp->xpath; + + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_CGI, &qinfo, &cgi) >= 0 && cgi.cgi) { if (tmp->idxfile) { @@ -2555,7 +2562,13 @@ static int attempt_cgi ( if (!st.isdir) { - if (server_xtn->query (httpd, client->server, req, tmp->xpath, QSE_HTTPD_SERVERSTD_CGI, &cgi) >= 0 && cgi.cgi) + qse_httpd_serverstd_query_info_t qinfo; + + QSE_MEMSET (&qinfo, 0, QSE_SIZEOF(qinfo)); + qinfo.req = req; + qinfo.xpath = tmp->xpath; + + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_CGI, &qinfo, &cgi) >= 0 && cgi.cgi) { /* the script name is composed of the orginal query path. * the pointer held in 'slash' is valid for tmp->qpath as @@ -2620,6 +2633,8 @@ static int make_resource ( qse_httpd_stat_t st; int n, stx, acc; + qse_httpd_serverstd_query_info_t qinfo; + QSE_MEMSET (&tmp, 0, QSE_SIZEOF(tmp)); tmp.qpath = qse_htre_getqpath(req); tmp.qpath_len = qse_mbslen (tmp.qpath); @@ -2628,6 +2643,10 @@ static int make_resource ( server_xtn = qse_httpd_getserverxtn (httpd, client->server); + QSE_MEMSET (&qinfo, 0, QSE_SIZEOF(qinfo)); + qinfo.req = req; + +#if 0 mth = qse_htre_getqmethodtype (req); if (mth == QSE_HTTP_CONNECT) { @@ -2653,7 +2672,7 @@ static int make_resource ( } /* pseudonym for raw proxying should not be useful. but set it for consistency */ - if (server_xtn->query (httpd, client->server, QSE_NULL, QSE_NULL, QSE_HTTPD_SERVERSTD_PSEUDONYM, &target->u.proxy.pseudonym) <= -1) + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_PSEUDONYM, &qinfo, &target->u.proxy.pseudonym) <= -1) target->u.proxy.pseudonym = QSE_NULL; /******************************************************************/ @@ -2693,11 +2712,11 @@ static int make_resource ( { /* make the source binding type the same as destination */ if (qse_getnwadport(&target->u.proxy.dst.nwad) == 0) - qse_setnwadport (&target->u.proxy.dst.nwad, qse_hton16(80)); + qse_setnwadport (&target->u.proxy.dst.nwad, qse_hton16(QSE_HTTPD_DEFAULT_PORT)); target->u.proxy.src.nwad.type = target->u.proxy.dst.nwad.type; } - if (server_xtn->query (httpd, client->server, QSE_NULL, QSE_NULL, QSE_HTTPD_SERVERSTD_PSEUDONYM, &target->u.proxy.pseudonym) <= -1) + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_PSEUDONYM, &qinfo, &target->u.proxy.pseudonym) <= -1) target->u.proxy.pseudonym = QSE_NULL; /* TODO: refrain from manipulating the request like this */ @@ -2705,7 +2724,7 @@ static int make_resource ( /******************************************************************/ /*TODO: load this from configuration. reamove this after debugging */ -target->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_URS; +//target->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_URS; /******************************************************************/ /* mark that this request is going to be proxied. */ @@ -2714,7 +2733,9 @@ target->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_URS; } } - if (server_xtn->query (httpd, client->server, req, QSE_NULL, QSE_HTTPD_SERVERSTD_ROOT, &tmp.root) <= -1) return -1; +#endif + + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_ROOT, &qinfo, &tmp.root) <= -1) return -1; switch (tmp.root.type) { case QSE_HTTPD_SERVERSTD_ROOT_NWAD: @@ -2730,7 +2751,7 @@ target->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_URS; target->u.proxy.dst.nwad = tmp.root.u.nwad; target->u.proxy.src.nwad.type = target->u.proxy.dst.nwad.type; - if (server_xtn->query (httpd, client->server, QSE_NULL, QSE_NULL, QSE_HTTPD_SERVERSTD_PSEUDONYM, &target->u.proxy.pseudonym) <= -1) + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_PSEUDONYM, &qinfo, &target->u.proxy.pseudonym) <= -1) target->u.proxy.pseudonym = QSE_NULL; /* mark that this request is going to be proxied. */ @@ -2742,13 +2763,24 @@ target->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_URS; target->u.text.ptr = tmp.root.u.text.ptr; target->u.text.mime = tmp.root.u.text.mime; return 0; + + case QSE_HTTPD_SERVERSTD_ROOT_PROXY: + target->type = QSE_HTTPD_RSRC_PROXY; + target->u.proxy = tmp.root.u.proxy; + req->attr.flags |= QSE_HTRE_ATTR_PROXIED; + return 0; + + case QSE_HTTPD_SERVERSTD_ROOT_ERROR: + target->type = QSE_HTTPD_RSRC_ERROR; + target->u.error.code = tmp.root.u.error.code; + return 0; } /* handle the request locally */ QSE_ASSERT (tmp.root.type == QSE_HTTPD_SERVERSTD_ROOT_PATH); - if (server_xtn->query (httpd, client->server, req, QSE_NULL, QSE_HTTPD_SERVERSTD_REALM, &tmp.realm) <= -1 || - server_xtn->query (httpd, client->server, req, QSE_NULL, QSE_HTTPD_SERVERSTD_INDEX, &tmp.index) <= -1) + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_REALM, &qinfo, &tmp.realm) <= -1 || + server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_INDEX, &qinfo, &tmp.index) <= -1) { return -1; } @@ -2792,7 +2824,7 @@ target->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_URS; tmp.auth.key.ptr = server_xtn->auth.ptr; tmp.auth.key.len = authl2; - if (server_xtn->query (httpd, client->server, req, QSE_NULL, QSE_HTTPD_SERVERSTD_AUTH, &tmp.auth) >= 0 && tmp.auth.authok) goto auth_ok; + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_AUTH, &qinfo, &tmp.auth) >= 0 && tmp.auth.authok) goto auth_ok; } } @@ -2825,8 +2857,8 @@ auth_ok: { /* Expectation Failed */ qse_htre_discardcontent (req); - target->type = QSE_HTTPD_RSRC_ERR; - target->u.err.code = 417; + target->type = QSE_HTTPD_RSRC_ERROR; + target->u.error.code = 417; return 0; } } @@ -2891,12 +2923,14 @@ auth_ok: } } + qinfo.xpath = tmp.xpath; + /* it is a directory - should i allow it? */ - if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DIRACC, &target->u.err.code) <= -1) target->u.err.code = 500; - if (target->u.err.code < 200 || target->u.err.code > 299) + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_DIRACC, &qinfo, &target->u.error.code) <= -1) target->u.error.code = 500; + if (target->u.error.code < 200 || target->u.error.code > 299) { qse_htre_discardcontent (req); - target->type = QSE_HTTPD_RSRC_ERR; + target->type = QSE_HTTPD_RSRC_ERROR; /* free xpath since it won't be used */ QSE_MMGR_FREE (httpd->mmgr, tmp.xpath); } @@ -2913,8 +2947,8 @@ auth_ok: { target->type = QSE_HTTPD_RSRC_DIR; target->u.dir.path = tmp.xpath; - if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DIRHEAD, &target->u.dir.head) <= -1) target->u.dir.head = QSE_NULL; - if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DIRFOOT, &target->u.dir.foot) <= -1) target->u.dir.foot = QSE_NULL; + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_DIRHEAD, &qinfo, &target->u.dir.head) <= -1) target->u.dir.head = QSE_NULL; + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_DIRFOOT, &qinfo, &target->u.dir.foot) <= -1) target->u.dir.foot = QSE_NULL; } } else @@ -2937,18 +2971,19 @@ auth_ok: } if (n >= 1) return 0; - acc = (tmp.idxfile || !qse_mbsend(tmp.qpath, QSE_MT("/")))? - QSE_HTTPD_SERVERSTD_FILEACC: QSE_HTTPD_SERVERSTD_DIRACC; + qinfo.xpath = tmp.xpath; /* check file's access permission */ - if (server_xtn->query (httpd, client->server, req, tmp.xpath, acc, &target->u.err.code) <= -1) target->u.err.code = 500; + acc = (tmp.idxfile || !qse_mbsend(tmp.qpath, QSE_MT("/")))? + QSE_HTTPD_SERVERSTD_FILEACC: QSE_HTTPD_SERVERSTD_DIRACC; + if (server_xtn->query (httpd, client->server, acc, &qinfo, &target->u.error.code) <= -1) target->u.error.code = 500; - if (target->u.err.code < 200 || target->u.err.code > 299) + if (target->u.error.code < 200 || target->u.error.code > 299) { /* free xpath since it won't be used */ qse_htre_discardcontent (req); QSE_MMGR_FREE (httpd->mmgr, tmp.xpath); - target->type = QSE_HTTPD_RSRC_ERR; + target->type = QSE_HTTPD_RSRC_ERROR; } else { @@ -2970,15 +3005,15 @@ auth_ok: target->type = QSE_HTTPD_RSRC_DIR; target->u.dir.path = tmp.xpath; - if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DIRHEAD, &target->u.dir.head) <= -1) target->u.dir.head = QSE_NULL; - if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_DIRFOOT, &target->u.dir.foot) <= -1) target->u.dir.foot = QSE_NULL; + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_DIRHEAD, &qinfo, &target->u.dir.head) <= -1) target->u.dir.head = QSE_NULL; + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_DIRFOOT, &qinfo, &target->u.dir.foot) <= -1) target->u.dir.foot = QSE_NULL; } else { target->type = QSE_HTTPD_RSRC_FILE; target->u.file.path = tmp.xpath; - if (server_xtn->query (httpd, client->server, req, tmp.xpath, QSE_HTTPD_SERVERSTD_MIME, &target->u.file.mime) <= -1) + if (server_xtn->query (httpd, client->server, QSE_HTTPD_SERVERSTD_MIME, &qinfo, &target->u.file.mime) <= -1) { /* don't care about failure */ target->u.file.mime = QSE_NULL; @@ -3026,8 +3061,9 @@ static struct cgi_tab_t cgitab[] = static int query_server ( qse_httpd_t* httpd, qse_httpd_server_t* server, - qse_htre_t* req, const qse_mchar_t* xpath, - qse_httpd_serverstd_query_code_t code, void* result) + qse_httpd_serverstd_query_code_t code, + const qse_httpd_serverstd_query_info_t* qinfo, + void* result) { qse_size_t i; @@ -3077,7 +3113,7 @@ static int query_server ( qse_httpd_serverstd_cgi_t* cgi = (qse_httpd_serverstd_cgi_t*)result; for (i = 0; i < QSE_COUNTOF(cgitab); i++) { - if (qse_mbsend (xpath, cgitab[i].suffix)) + if (qse_mbsend (qinfo->xpath, cgitab[i].suffix)) { QSE_MEMCPY (cgi, &cgitab[i].cgi, QSE_SIZEOF(*cgi)); return 0; @@ -3092,7 +3128,7 @@ static int query_server ( /* TODO: binary search if the table is large */ for (i = 0; i < QSE_COUNTOF(mimetab); i++) { - if (qse_mbsend (xpath, mimetab[i].suffix)) + if (qse_mbsend (qinfo->xpath, mimetab[i].suffix)) { *(const qse_mchar_t**)result = mimetab[i].type; return 0; @@ -3108,7 +3144,7 @@ static int query_server ( /* i don't allow PUT or DELET by default. * override this query result if you want to change * the behavior. */ - switch (qse_htre_getqmethodtype(req)) + switch (qse_htre_getqmethodtype(qinfo->req)) { case QSE_HTTP_OPTIONS: case QSE_HTTP_HEAD: diff --git a/qse/lib/http/httpd-task.c b/qse/lib/http/httpd-task.c index ffee69f9..21f67aae 100644 --- a/qse/lib/http/httpd-task.c +++ b/qse/lib/http/httpd-task.c @@ -390,8 +390,8 @@ qse_httpd_task_t* qse_httpd_entaskrsrc ( task = qse_httpd_entaskdir (httpd, client, pred, &rsrc->u.dir, req); break; - case QSE_HTTPD_RSRC_ERR: - task = qse_httpd_entaskerr (httpd, client, pred, rsrc->u.err.code, req); + case QSE_HTTPD_RSRC_ERROR: + task = qse_httpd_entaskerr (httpd, client, pred, rsrc->u.error.code, req); break; case QSE_HTTPD_RSRC_FILE: