diff --git a/qse/cmd/http/httpd.c b/qse/cmd/http/httpd.c index 1e8b555f..e38a3be7 100644 --- a/qse/cmd/http/httpd.c +++ b/qse/cmd/http/httpd.c @@ -152,8 +152,20 @@ struct loccfg_t qse_mchar_t* xcfg[XCFG_MAX]; - int root_is_nwad; - qse_nwad_t root_nwad; + enum + { + ROOT_TYPE_PATH = 0, + ROOT_TYPE_NWAD, + ROOT_TYPE_RELOC, + ROOT_TYPE_ERROR + } root_type; + union + { + qse_nwad_t nwad; + int error_code; + qse_httpd_rsrc_reloc_t reloc; + } root; + struct { qse_size_t count; @@ -521,6 +533,7 @@ static int get_server_root ( } } +/* TODO: handle https:// .... */ if (loccfg->proxy.allow_http && qse_mbszcasecmp (qpath, QSE_MT("http://"), 7) == 0) { @@ -573,25 +586,44 @@ static int get_server_root ( } } - if (loccfg->root_is_nwad) + switch (loccfg->root_type) { - /* simple forwarding. it's not controlled by proxy.http or proxy.connect */ - root->type = QSE_HTTPD_SERVERSTD_ROOT_PROXY; + case ROOT_TYPE_NWAD: + /* simple forwarding. it's not controlled by proxy.http or proxy.connect */ + root->type = QSE_HTTPD_SERVERSTD_ROOT_PROXY; - root->u.proxy.dst.nwad = loccfg->root_nwad; - root->u.proxy.src.nwad.type = root->u.proxy.dst.nwad.type; + root->u.proxy.dst.nwad = loccfg->root.nwad; + root->u.proxy.src.nwad.type = root->u.proxy.dst.nwad.type; - if (loccfg->proxy.pseudonym[0]) - root->u.proxy.pseudonym = loccfg->proxy.pseudonym; + if (loccfg->proxy.pseudonym[0]) + root->u.proxy.pseudonym = loccfg->proxy.pseudonym; - goto proxy_ok; + goto proxy_ok; + + case ROOT_TYPE_RELOC: + root->type = QSE_HTTPD_SERVERSTD_ROOT_RELOC; + root->u.reloc.flags = loccfg->root.reloc.flags; + root->u.reloc.target = qse_mbsdup (loccfg->root.reloc.target, qse_httpd_getmmgr(httpd)); + if (root->u.reloc.target == QSE_NULL) + { + root->type = QSE_HTTPD_SERVERSTD_ROOT_ERROR; + root->u.error.code = 500; /* internal server error */ + } + break; + + case ROOT_TYPE_ERROR: + root->type = QSE_HTTPD_SERVERSTD_ROOT_ERROR; + root->u.error.code = loccfg->root.error_code; + break; + + default: + /* local file system */ + root->type = QSE_HTTPD_SERVERSTD_ROOT_PATH; + root->u.path.val = loccfg->xcfg[XCFG_ROOT]; + root->u.path.rpl = loccfg->locname.len; + break; } - - /* local file system */ - root->type = QSE_HTTPD_SERVERSTD_ROOT_PATH; - root->u.path.val = loccfg->xcfg[XCFG_ROOT]; - root->u.path.rpl = loccfg->locname.len; return 0; proxy_ok: @@ -1624,11 +1656,70 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_t* xli, qse_xli_list_t* list } #endif - if (cfg->xcfg[XCFG_ROOT] && qse_mbstonwad (cfg->xcfg[XCFG_ROOT], &cfg->root_nwad) >= 0) + cfg->root_type = ROOT_TYPE_PATH; /* default type */ + + if (cfg->xcfg[XCFG_ROOT]) { - cfg->root_is_nwad = 1; + /* check if the root value is special */ + const qse_mchar_t* root = cfg->xcfg[XCFG_ROOT]; + + if (root[0] == QSE_MT('<') && QSE_ISMDIGIT(root[1])) + { + int code = 0; + + root++; + while (QSE_ISMDIGIT(*root)) + { + code = code * 10 + (*root - QSE_MT('0')); + root++; + } + + if (code >= 400 && code <= 599 && root[0] == QSE_MT('>') && root[1] == QSE_MT('\0')) + { + cfg->root_type = ROOT_TYPE_ERROR; + cfg->root.error_code = code; + goto done; + } + + if ((code == 301 || code == 302 || code == 303 || code == 307 || code == 308) && *root == QSE_MT('>')) + { + root++; + if (QSE_ISMPRINT(*root)) + { + cfg->root_type = ROOT_TYPE_RELOC; + cfg->root.reloc.flags = 0; + switch (code) + { + case 308: + cfg->root.reloc.flags |= QSE_HTTPD_RSRC_RELOC_PERMANENT; + /* fall thru */ + case 307: + cfg->root.reloc.flags |= QSE_HTTPD_RSRC_RELOC_KEEPMETHOD; + break; + + case 301: + cfg->root.reloc.flags |= QSE_HTTPD_RSRC_RELOC_PERMANENT; + break; + } + cfg->root.reloc.target = root; + goto done; + } + } + } + + if (qse_mbstonwad (cfg->xcfg[XCFG_ROOT], &cfg->root.nwad) >= 0) + { + if (cfg->root.nwad.type != QSE_NWAD_IN4 && cfg->root.nwad.type != QSE_NWAD_IN6) + { + qse_printf (QSE_T("ERROR: invalid address for root - [%hs]\n"), cfg->xcfg[XCFG_ROOT]); + return -1; + } + cfg->root_type = ROOT_TYPE_NWAD; + goto done; + } } +done: return 0; } diff --git a/qse/cmd/http/httpd.conf b/qse/cmd/http/httpd.conf index 6ff42b1a..5cc950f3 100644 --- a/qse/cmd/http/httpd.conf +++ b/qse/cmd/http/httpd.conf @@ -29,12 +29,14 @@ server-default { #################################################################### root = "/var/www"; #root = "1.2.3.4:80"; + #root = "<302>http://www.google.com"; #301, 302, 303, 307, 308 + #root = "<404>"; #400 - 599 # pseudonym to use in Via: for proxying #pseudonym = "my-host"; realm = "default realm"; - auth = "username:password"; + auth = "username:password"; index = "index.html", "index.cgi"; diff --git a/qse/include/qse/http/httpd.h b/qse/include/qse/http/httpd.h index 20b005fe..0458f6a0 100644 --- a/qse/include/qse/http/httpd.h +++ b/qse/include/qse/http/httpd.h @@ -830,7 +830,7 @@ typedef struct qse_httpd_rsrc_reloc_t qse_httpd_rsrc_reloc_t; struct qse_httpd_rsrc_reloc_t { int flags; /**< 0 or bitwise-ORed of #qse_httpd_rsrc_reloc_flag_t */ - const qse_mchar_t* dst; + const qse_mchar_t* target; }; typedef struct qse_httpd_rsrc_t qse_httpd_rsrc_t; @@ -848,7 +848,7 @@ struct qse_httpd_rsrc_t qse_httpd_rsrc_cgi_t cgi; qse_httpd_rsrc_dir_t dir; - struct + struct { int code; } error; @@ -1095,11 +1095,11 @@ QSE_EXPORT qse_httpd_task_t* qse_httpd_entasktext ( qse_htre_t* req ); -QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskerr ( +QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskerror ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* pred, - int code, + int code, qse_htre_t* req ); diff --git a/qse/lib/http/httpd-cgi.c b/qse/lib/http/httpd-cgi.c index 430c3fc4..d19f8f63 100644 --- a/qse/lib/http/httpd-cgi.c +++ b/qse/lib/http/httpd-cgi.c @@ -1414,7 +1414,7 @@ printf ("task_main_cgi_2 trigger[0].mask=%d trigger[1].mask=%d cmask=%d\n", return 1; oops: - return (qse_httpd_entask_err (httpd, client, task, 500, cgi->method, &cgi->version, cgi->keepalive) == QSE_NULL)? -1: 0; + return (qse_httpd_entask_error (httpd, client, task, 500, cgi->method, &cgi->version, cgi->keepalive) == QSE_NULL)? -1: 0; } static int task_main_cgi ( @@ -1578,7 +1578,7 @@ oops: cgi->script_htrd = QSE_NULL; } - return (qse_httpd_entask_err ( + return (qse_httpd_entask_error ( httpd, client, task, http_errnum, cgi->method, &cgi->version, cgi->keepalive) == QSE_NULL)? -1: 0; } diff --git a/qse/lib/http/httpd-dir.c b/qse/lib/http/httpd-dir.c index 2e80d280..24b9e4a5 100644 --- a/qse/lib/http/httpd-dir.c +++ b/qse/lib/http/httpd-dir.c @@ -586,7 +586,7 @@ qse_httpd_task_t* qse_httpd_entaskdir ( int status; status = (httpd->errnum == QSE_HTTPD_ENOENT)? 404: (httpd->errnum == QSE_HTTPD_EACCES)? 403: 500; - return qse_httpd_entaskerr (httpd, client, pred, status, req); + return qse_httpd_entaskerror (httpd, client, pred, status, req); } else { @@ -643,7 +643,7 @@ qse_httpd_task_t* qse_httpd_entaskdir ( } } - return qse_httpd_entaskerr (httpd, client, pred, status, req); + return qse_httpd_entaskerror (httpd, client, pred, status, req); } @@ -657,11 +657,11 @@ qse_httpd_task_t* qse_httpd_entaskdir ( (httpd->errnum == QSE_HTTPD_EACCES)? 403: 500; } - return qse_httpd_entaskerr (httpd, client, pred, status, req); + return qse_httpd_entaskerror (httpd, client, pred, status, req); } default: /* Method not allowed */ - return qse_httpd_entaskerr (httpd, client, pred, 405, req); + return qse_httpd_entaskerror (httpd, client, pred, 405, req); } } diff --git a/qse/lib/http/httpd-file.c b/qse/lib/http/httpd-file.c index 6ec079ec..a15ab2bc 100644 --- a/qse/lib/http/httpd-file.c +++ b/qse/lib/http/httpd-file.c @@ -191,7 +191,7 @@ static QSE_INLINE int task_main_getfile ( int http_errnum; http_errnum = (httpd->errnum == QSE_HTTPD_ENOENT)? 404: (httpd->errnum == QSE_HTTPD_EACCES)? 403: 500; - x = qse_httpd_entask_err ( + x = qse_httpd_entask_error ( httpd, client, x, http_errnum, file->method, &file->version, file->keepalive); goto no_file_send; @@ -203,7 +203,7 @@ static QSE_INLINE int task_main_getfile ( int http_errnum; http_errnum = (httpd->errnum == QSE_HTTPD_ENOENT)? 404: (httpd->errnum == QSE_HTTPD_EACCES)? 403: 500; - x = qse_httpd_entask_err ( + x = qse_httpd_entask_error ( httpd, client, x, http_errnum, file->method, &file->version, file->keepalive); goto no_file_send; @@ -226,7 +226,7 @@ static QSE_INLINE int task_main_getfile ( if (file->u.get.range.from >= st.size) { - x = qse_httpd_entask_err ( + x = qse_httpd_entask_error ( httpd, client, x, 416, file->method, &file->version, file->keepalive); goto no_file_send; } @@ -491,7 +491,7 @@ static int task_main_putfile_2 ( /* snatching is over. writing error may have occurred as well. * file->u.put.status should hold a proper status code */ - if (qse_httpd_entask_err ( + if (qse_httpd_entask_error ( httpd, client, task, file->u.put.status, file->method, &file->version, file->keepalive) == QSE_NULL) return -1; return 0; /* no more data to read. task over */ @@ -516,7 +516,7 @@ static int task_main_putfile ( * note: if initialization error occurred and there is contents for the * client to send, this reply may get to the client before it finishes * sending the contents. */ - if (qse_httpd_entask_err ( + if (qse_httpd_entask_error ( httpd, client, task, file->u.put.status, file->method, &file->version, file->keepalive) == QSE_NULL) return -1; return 0; /* task over */ @@ -603,7 +603,7 @@ qse_httpd_task_t* qse_httpd_entaskfile ( /*while (tmp->next) tmp = tmp->next;*/ /* get the last value */ if (qse_parsehttprange (tmp->ptr, &data.u.get.range) <= -1) { - return qse_httpd_entaskerr (httpd, client, pred, 416, req); + return qse_httpd_entaskerror (httpd, client, pred, 416, req); } } else @@ -638,13 +638,13 @@ qse_httpd_task_t* qse_httpd_entaskfile ( (httpd->errnum == QSE_HTTPD_EACCES)? 403: 500; } - return qse_httpd_entaskerr (httpd, client, pred, status, req); + return qse_httpd_entaskerror (httpd, client, pred, status, req); } default: /* Method not allowed */ qse_htre_discardcontent (req); - return qse_httpd_entaskerr (httpd, client, pred, 405, req); + return qse_httpd_entaskerror (httpd, client, pred, 405, req); } } diff --git a/qse/lib/http/httpd-proxy.c b/qse/lib/http/httpd-proxy.c index 802f6b62..2c820ad4 100644 --- a/qse/lib/http/httpd-proxy.c +++ b/qse/lib/http/httpd-proxy.c @@ -1865,7 +1865,7 @@ qse_printf (QSE_T("TRAILING DATA=%d, [%hs]\n"), (int)QSE_MBS_LEN(proxy->res), QS oops: if (proxy->resflags & PROXY_RES_EVER_SENTBACK) return -1; - return (qse_httpd_entask_err (httpd, client, task, http_errnum, proxy->method, &proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0; + return (qse_httpd_entask_error (httpd, client, task, http_errnum, proxy->method, &proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0; } static int task_main_proxy_1 ( @@ -1958,7 +1958,7 @@ static int task_main_proxy_1 ( return 1; oops: - return (qse_httpd_entask_err (httpd, client, task, http_errnum, proxy->method, &proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0; + return (qse_httpd_entask_error (httpd, client, task, http_errnum, proxy->method, &proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0; } static void on_peer_name_resolved (qse_httpd_t* httpd, const qse_mchar_t* name, const qse_nwad_t* nwad, void* ctx) @@ -2062,7 +2062,7 @@ printf ("XXXXXXXXXXXXXXXXXXXXXXXXXX URL REWRITTEN TO [%s].....\n", new_url); /* relocation code is given explictly, no slash appending is needed. * use qse_httpd_entask_status() rather than qse_httpd_entaskreloc(). */ reloc.flags = 0; - reloc.dst = nuptr; + reloc.target = nuptr; if (qse_httpd_entask_status ( httpd, proxy->client, proxy->task, redir_code, &reloc, @@ -2402,7 +2402,7 @@ oops: proxy->peer_htrd = QSE_NULL; } - return (qse_httpd_entask_err ( + return (qse_httpd_entask_error ( httpd, client, task, http_errnum, proxy->method, &proxy->version, proxy->keepalive) == QSE_NULL)? -1: 0; } diff --git a/qse/lib/http/httpd-std.c b/qse/lib/http/httpd-std.c index 6443dfd5..c2038551 100644 --- a/qse/lib/http/httpd-std.c +++ b/qse/lib/http/httpd-std.c @@ -2189,7 +2189,7 @@ if (qse_htre_getcontentlen(req) > 0) /* POST without Content-Length nor not chunked */ req->flags &= ~QSE_HTRE_ATTR_KEEPALIVE; qse_httpd_discardcontent (httpd, req); - task = qse_httpd_entaskerr (httpd, client, QSE_NULL, 411, req); + task = qse_httpd_entaskerror (httpd, client, QSE_NULL, 411, req); if (task) { /* 411 Length Required - can't keep alive. Force disconnect */ @@ -2204,7 +2204,7 @@ if (qse_htre_getcontentlen(req) > 0) * 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); + task = qse_httpd_entaskerror (httpd, client, QSE_NULL, 500, req); } else { @@ -2252,7 +2252,7 @@ printf ("CANOT MAKE RESOURCE.... %s\n", qse_htre_getqpath(req)); * '500 Internal Server Error'. If it wants to return a specific * error code, it should return 0 with the QSE_HTTPD_RSRC_ERROR * resource. */ - task = qse_httpd_entaskerr (httpd, client, QSE_NULL, 500, req); + task = qse_httpd_entaskerror (httpd, client, QSE_NULL, 500, req); } else { @@ -2494,8 +2494,8 @@ static void free_resource ( break; case QSE_HTTPD_RSRC_RELOC: - if (target->u.reloc.dst != qpath) - QSE_MMGR_FREE (httpd->mmgr, (qse_mchar_t*)target->u.reloc.dst); + if (target->u.reloc.target != qpath) + QSE_MMGR_FREE (httpd->mmgr, (qse_mchar_t*)target->u.reloc.target); break; default: @@ -2608,8 +2608,8 @@ static int attempt_cgi ( /* create a relocation resource */ QSE_MEMSET (target, 0, QSE_SIZEOF(*target)); target->type = QSE_HTTPD_RSRC_RELOC; - target->u.reloc.dst = merge_paths (httpd, tmp->qpath, tmp->idxfile); - if (target->u.reloc.dst == QSE_NULL) goto oops; + target->u.reloc.target = merge_paths (httpd, tmp->qpath, tmp->idxfile); + if (target->u.reloc.target == QSE_NULL) goto oops; /* free tmp->xpath here upon success since it's not used for relocation. * upon failure, it is freed by the caller. so the 'oops' part @@ -3022,7 +3022,7 @@ auth_ok: qse_htre_discardcontent (req); target->type = QSE_HTTPD_RSRC_RELOC; target->u.reloc.flags = QSE_HTTPD_RSRC_RELOC_APPENDSLASH | QSE_HTTPD_RSRC_RELOC_PERMANENT; - target->u.reloc.dst = tmp.qpath; + target->u.reloc.target = tmp.qpath; /* free xpath since it won't be used */ QSE_MMGR_FREE (httpd->mmgr, tmp.xpath); } @@ -3089,8 +3089,8 @@ auth_ok: /* create a relocation resource */ target->type = QSE_HTTPD_RSRC_RELOC; - target->u.reloc.dst = merge_paths (httpd, tmp.qpath, tmp.idxfile); - if (target->u.reloc.dst == QSE_NULL) return -1; + target->u.reloc.target = merge_paths (httpd, tmp.qpath, tmp.idxfile); + if (target->u.reloc.target == QSE_NULL) return -1; } else if (acc == QSE_HTTPD_SERVERSTD_DIRACC) { diff --git a/qse/lib/http/httpd-task.c b/qse/lib/http/httpd-task.c index b533b500..12419ebc 100644 --- a/qse/lib/http/httpd-task.c +++ b/qse/lib/http/httpd-task.c @@ -188,7 +188,7 @@ qse_httpd_task_t* qse_httpd_entask_status ( reloc = (qse_httpd_rsrc_reloc_t*)extra; extrapre = QSE_MT("Location: "); extrapst = (reloc->flags & QSE_HTTPD_RSRC_RELOC_APPENDSLASH)? QSE_MT("/\r\n"): QSE_MT("\r\n"); - extraval = reloc->dst; + extraval = reloc->target; break; } @@ -228,7 +228,7 @@ qse_httpd_task_t* qse_httpd_entask_status ( } /*------------------------------------------------------------------------*/ -qse_httpd_task_t* qse_httpd_entask_err ( +qse_httpd_task_t* qse_httpd_entask_error ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* pred, int code, qse_http_method_t method, const qse_http_version_t* version, int keepalive) @@ -236,7 +236,7 @@ qse_httpd_task_t* qse_httpd_entask_err ( return qse_httpd_entask_status (httpd, client, pred, code, QSE_NULL, method, version, keepalive); } -qse_httpd_task_t* qse_httpd_entaskerr ( +qse_httpd_task_t* qse_httpd_entaskerror ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* pred, int code, qse_htre_t* req) { @@ -384,7 +384,7 @@ qse_httpd_task_t* qse_httpd_entaskrsrc ( break; case QSE_HTTPD_RSRC_ERROR: - task = qse_httpd_entaskerr (httpd, client, pred, rsrc->u.error.code, req); + task = qse_httpd_entaskerror (httpd, client, pred, rsrc->u.error.code, req); break; case QSE_HTTPD_RSRC_FILE: diff --git a/qse/lib/http/httpd-text.c b/qse/lib/http/httpd-text.c index 377cef10..625579c7 100644 --- a/qse/lib/http/httpd-text.c +++ b/qse/lib/http/httpd-text.c @@ -102,7 +102,7 @@ qse_httpd_task_t* qse_httpd_entasktext ( default: /* Method not allowed */ - return qse_httpd_entaskerr (httpd, client, pred, 405, req); + return qse_httpd_entaskerror (httpd, client, pred, 405, req); } qse_fmtuintmaxtombs (b_tlen, QSE_COUNTOF(b_tlen), tlen, 10, -1, QSE_MT('\0'), QSE_NULL); diff --git a/qse/lib/http/httpd.h b/qse/lib/http/httpd.h index 6770c200..a98ab754 100644 --- a/qse/lib/http/httpd.h +++ b/qse/lib/http/httpd.h @@ -131,7 +131,7 @@ qse_httpd_task_t* qse_httpd_entask_status ( int keepalive ); -qse_httpd_task_t* qse_httpd_entask_err ( +qse_httpd_task_t* qse_httpd_entask_error ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* pred,