diff --git a/qse/include/qse/cmn/str.h b/qse/include/qse/cmn/str.h index dded784b..56600e66 100644 --- a/qse/include/qse/cmn/str.h +++ b/qse/include/qse/cmn/str.h @@ -994,11 +994,13 @@ qse_mchar_t* qse_mbsxdup2 ( qse_mchar_t* qse_mbsadup ( const qse_mchar_t* str[], + qse_size_t* len, qse_mmgr_t* mmgr ); qse_mchar_t* qse_mbsxadup ( const qse_mcstr_t str[], + qse_size_t* len, qse_mmgr_t* mmgr ); @@ -1029,11 +1031,13 @@ qse_wchar_t* qse_wcsxdup2 ( qse_wchar_t* qse_wcsadup ( const qse_wchar_t* str[], + qse_size_t* len, qse_mmgr_t* mmgr ); qse_wchar_t* qse_wcsxadup ( const qse_wcstr_t str[], + qse_size_t* len, qse_mmgr_t* mmgr ); @@ -1042,15 +1046,15 @@ qse_wchar_t* qse_wcsxadup ( # define qse_strdup2(s1,s2,mmgr) qse_mbsdup2(s1,s2,mmgr) # define qse_strxdup(s,l,mmgr) qse_mbsxdup(s,l,mmgr) # define qse_strxdup2(s1,l1,s2,l2,mmgr) qse_mbsxdup(s1,l1,s2,l2,mmgr) -# define qse_stradup(sa,mmgr) qse_mbsadup(sa,mmgr) -# define qse_strxadup(sa,mmgr) qse_mbsxadup(sa,mmgr) +# define qse_stradup(sa,len,mmgr) qse_mbsadup(sa,len,mmgr) +# define qse_strxadup(sa,len,mmgr) qse_mbsxadup(sa,len,mmgr) #else # define qse_strdup(s,mmgr) qse_wcsdup(s,mmgr) # define qse_strdup2(s1,s2,mmgr) qse_wcsdup2(s1,s2,mmgr) # define qse_strxdup(s,l,mmgr) qse_wcsxdup(s,l,mmgr) # define qse_strxdup2(s1,l1,s2,l2,mmgr) qse_wcsxdup(s1,l1,s2,l2,mmgr) -# define qse_stradup(sa,mmgr) qse_wcsadup(sa,mmgr) -# define qse_strxadup(sa,mmgr) qse_wcsxadup(sa,mmgr) +# define qse_stradup(sa,len,mmgr) qse_wcsadup(sa,len,mmgr) +# define qse_strxadup(sa,len,mmgr) qse_wcsxadup(sa,len,mmgr) #endif /** diff --git a/qse/include/qse/net/http.h b/qse/include/qse/net/http.h index 73e0e4c2..543dffdd 100644 --- a/qse/include/qse/net/http.h +++ b/qse/include/qse/net/http.h @@ -163,6 +163,10 @@ int qse_comparehttpversions ( const qse_http_version_t* v2 ); +const qse_mchar_t* qse_httpstatustombs ( + int code +); + const qse_mchar_t* qse_httpmethodtombs ( qse_http_method_t type ); diff --git a/qse/include/qse/net/httpd.h b/qse/include/qse/net/httpd.h index d1d341a4..de4d1969 100644 --- a/qse/include/qse/net/httpd.h +++ b/qse/include/qse/net/httpd.h @@ -46,6 +46,7 @@ enum qse_httpd_errnum_t QSE_HTTPD_EEXIST, QSE_HTTPD_EINTR, QSE_HTTPD_EAGAIN, + QSE_HTTPD_ENOBUF, QSE_HTTPD_EIOMUX, QSE_HTTPD_EDISCON, /* client disconnnected */ @@ -255,6 +256,14 @@ struct qse_httpd_rcb_t qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req); int (*handle_request) ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req); + + int (*format_error) ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + int code, qse_mchar_t* buf, int bufsz); + int (*format_dir) ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + const qse_mchar_t* qpath, const qse_httpd_dirent_t* dirent, + qse_mchar_t* buf, int bufsz); }; typedef struct qse_httpd_task_t qse_httpd_task_t; @@ -358,6 +367,7 @@ enum qse_httpd_rsrc_type_t QSE_HTTPD_RSRC_FILE, QSE_HTTPD_RSRC_PROXY, QSE_HTTPD_RSRC_RELOC, + QSE_HTTPD_RSRC_REDIR, QSE_HTTPD_RSRC_TEXT }; typedef enum qse_httpd_rsrc_type_t qse_httpd_rsrc_type_t; @@ -384,7 +394,6 @@ struct qse_httpd_rsrc_t struct { const qse_mchar_t* path; - const qse_mchar_t* css; } dir; struct @@ -403,11 +412,17 @@ struct qse_httpd_rsrc_t qse_nwad_t dst; qse_nwad_t src; } proxy; + struct { const qse_mchar_t* dst; } reloc; + struct + { + const qse_mchar_t* dst; + } redir; + struct { const qse_mchar_t* ptr; @@ -488,7 +503,7 @@ enum qse_httpd_server_xtn_cfg_idx_t struct qse_httpd_server_xtn_t { - qse_mxstr_t cfg[QSE_HTTPD_SERVER_XTN_CFG_MAX]; + qse_mchar_t* cfg[QSE_HTTPD_SERVER_XTN_CFG_MAX]; qse_httpd_server_cbstd_t* cbstd; qse_httpd_server_cgistd_t* cgistd; qse_httpd_server_mimestd_t* mimestd; @@ -699,12 +714,27 @@ qse_httpd_task_t* qse_httpd_entaskreloc ( qse_htre_t* req ); +qse_httpd_task_t* qse_httpd_entaskredir ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_httpd_task_t* pred, + const qse_mchar_t* dst, + qse_htre_t* req +); + + +qse_httpd_task_t* qse_httpd_entasknomod ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_httpd_task_t* pred, + qse_htre_t* req +); + qse_httpd_task_t* qse_httpd_entaskdir ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* pred, const qse_mchar_t* name, - const qse_mchar_t* css, qse_htre_t* req ); diff --git a/qse/lib/cmn/fs-move.c b/qse/lib/cmn/fs-move.c index b352f548..edddd0f1 100644 --- a/qse/lib/cmn/fs-move.c +++ b/qse/lib/cmn/fs-move.c @@ -270,7 +270,7 @@ int qse_fs_move ( arr[2] = qse_basename(oldpath); arr[3] = QSE_NULL; #if defined(QSE_CHAR_IS_MCHAR) - fop.new_path2 = qse_stradup (arr, fs->mmgr); + fop.new_path2 = qse_stradup (arr, QSE_NULL, fs->mmgr); #else fop.new_path2 = qse_wcsatombsdup (arr, fs->mmgr); #endif diff --git a/qse/lib/cmn/fs.c b/qse/lib/cmn/fs.c index 4745f614..a34ac467 100644 --- a/qse/lib/cmn/fs.c +++ b/qse/lib/cmn/fs.c @@ -199,7 +199,7 @@ int qse_fs_chdir (qse_fs_t* fs, const qse_char_t* name) tmp_name[idx] = QSE_NULL; - fsname = qse_stradup (tmp_name, fs->mmgr); + fsname = qse_stradup (tmp_name, QSE_NULL, fs->mmgr); if (fsname == QSE_NULL) { fs->errnum = QSE_FS_ENOMEM; @@ -260,7 +260,7 @@ int qse_fs_chdir (qse_fs_t* fs, const qse_char_t* name) tmp_name[idx++] = name; tmp_name[idx] = QSE_NULL; - fsname = qse_stradup (tmp_name, fs->mmgr); + fsname = qse_stradup (tmp_name, QSE_NULL, fs->mmgr); if (fsname == QSE_NULL) { fs->errnum = QSE_FS_ENOMEM; @@ -453,7 +453,7 @@ qse_fs_ent_t* qse_fs_read (qse_fs_t* fs, int flags) tmp_name[1] = QSE_T("\\"); tmp_name[2] = info->wfd.cFileName; tmp_name[3] = QSE_NULL; - fname = qse_stradup (tmp_name, fs->mmgr); + fname = qse_stradup (tmp_name, QSE_NULL, fs->mmgr); if (fname == QSE_NULL) { fs->errnum = QSE_FS_ENOMEM; @@ -564,7 +564,7 @@ qse_fs_ent_t* qse_fs_read (qse_fs_t* fs, int flags) tmp_name[1] = QSE_MT("/"); tmp_name[2] = ent->d_name; tmp_name[3] = QSE_NULL; - mfname = qse_mbsadup (tmp_name, fs->mmgr); + mfname = qse_mbsadup (tmp_name, QSE_NULL, fs->mmgr); if (mfname == QSE_NULL) { fs->errnum = QSE_FS_ENOMEM; diff --git a/qse/lib/cmn/str-dup.c b/qse/lib/cmn/str-dup.c index ea611828..5381ff09 100644 --- a/qse/lib/cmn/str-dup.c +++ b/qse/lib/cmn/str-dup.c @@ -72,7 +72,7 @@ qse_mchar_t* qse_mbsxdup2 ( return tmp; } -qse_mchar_t* qse_mbsadup (const qse_mchar_t* str[], qse_mmgr_t* mmgr) +qse_mchar_t* qse_mbsadup (const qse_mchar_t* str[], qse_size_t* len, qse_mmgr_t* mmgr) { qse_mchar_t* buf, * ptr; qse_size_t i; @@ -88,10 +88,11 @@ qse_mchar_t* qse_mbsadup (const qse_mchar_t* str[], qse_mmgr_t* mmgr) ptr = buf; for (i = 0; str[i]; i++) ptr += qse_mbscpy (ptr, str[i]); + if (len) *len = capa; return buf; } -qse_mchar_t* qse_mbsxadup (const qse_mcstr_t str[], qse_mmgr_t* mmgr) +qse_mchar_t* qse_mbsxadup (const qse_mcstr_t str[], qse_size_t* len, qse_mmgr_t* mmgr) { qse_mchar_t* buf, * ptr; qse_size_t i; @@ -107,6 +108,7 @@ qse_mchar_t* qse_mbsxadup (const qse_mcstr_t str[], qse_mmgr_t* mmgr) ptr = buf; for (i = 0; str[i].ptr; i++) ptr += qse_mbsncpy (ptr, str[i].ptr, str[i].len); + if (len) *len = capa; return buf; } @@ -165,7 +167,7 @@ qse_wchar_t* qse_wcsxdup2 ( return tmp; } -qse_wchar_t* qse_wcsadup (const qse_wchar_t* str[], qse_mmgr_t* mmgr) +qse_wchar_t* qse_wcsadup (const qse_wchar_t* str[], qse_size_t* len, qse_mmgr_t* mmgr) { qse_wchar_t* buf, * ptr; qse_size_t i; @@ -181,10 +183,11 @@ qse_wchar_t* qse_wcsadup (const qse_wchar_t* str[], qse_mmgr_t* mmgr) ptr = buf; for (i = 0; str[i]; i++) ptr += qse_wcscpy (ptr, str[i]); + if (len) *len = capa; return buf; } -qse_wchar_t* qse_wcsxadup (const qse_wcstr_t str[], qse_mmgr_t* mmgr) +qse_wchar_t* qse_wcsxadup (const qse_wcstr_t str[], qse_size_t* len, qse_mmgr_t* mmgr) { qse_wchar_t* buf, * ptr; qse_size_t i; @@ -200,5 +203,6 @@ qse_wchar_t* qse_wcsxadup (const qse_wcstr_t str[], qse_mmgr_t* mmgr) ptr = buf; for (i = 0; str[i].ptr; i++) ptr += qse_wcsncpy (ptr, str[i].ptr, str[i].len); + if (len) *len = capa; return buf; } diff --git a/qse/lib/net/http.c b/qse/lib/net/http.c index ab3e12cb..0cc72864 100644 --- a/qse/lib/net/http.c +++ b/qse/lib/net/http.c @@ -34,6 +34,67 @@ int qse_comparehttpversions ( return v1->major - v2->major; } +const qse_mchar_t* qse_httpstatustombs (int code) +{ + const qse_mchar_t* msg; + + switch (code) + { + case 100: msg = QSE_MT("Continue"); break; + case 101: msg = QSE_MT("Switching Protocols"); break; + + case 200: msg = QSE_MT("OK"); break; + case 201: msg = QSE_MT("Created"); break; + case 202: msg = QSE_MT("Accepted"); break; + case 203: msg = QSE_MT("Non-Authoritative Information"); break; + case 204: msg = QSE_MT("No Content"); break; + case 205: msg = QSE_MT("Reset Content"); break; + case 206: msg = QSE_MT("Partial Content"); break; + + case 300: msg = QSE_MT("Multiple Choices"); break; + case 301: msg = QSE_MT("Moved Permanently"); break; + case 302: msg = QSE_MT("Found"); break; + case 303: msg = QSE_MT("See Other"); break; + case 304: msg = QSE_MT("Not Modified"); break; + case 305: msg = QSE_MT("Use Proxy"); break; + case 307: msg = QSE_MT("Temporary Redirect"); break; + + case 400: msg = QSE_MT("Bad Request"); break; + case 401: msg = QSE_MT("Unauthorized"); break; + case 402: msg = QSE_MT("Payment Required"); break; + case 403: msg = QSE_MT("Forbidden"); break; + case 404: msg = QSE_MT("Not Found"); break; + case 405: msg = QSE_MT("Method Not Allowed"); break; + case 406: msg = QSE_MT("Not Acceptable"); break; + case 407: msg = QSE_MT("Proxy Authentication Required"); break; + case 408: msg = QSE_MT("Request Timeout"); break; + case 409: msg = QSE_MT("Conflict"); break; + case 410: msg = QSE_MT("Gone"); break; + case 411: msg = QSE_MT("Length Required"); break; + case 412: msg = QSE_MT("Precondition Failed"); break; + case 413: msg = QSE_MT("Request Entity Too Large"); break; + case 414: msg = QSE_MT("Request-URI Too Long"); break; + case 415: msg = QSE_MT("Unsupported Media Type"); break; + case 416: msg = QSE_MT("Requested Range Not Satisfiable"); break; + case 417: msg = QSE_MT("Expectation Failed"); break; + case 426: msg = QSE_MT("Upgrade Required"); break; + case 428: msg = QSE_MT("Precondition Required"); break; + case 429: msg = QSE_MT("Too Many Requests"); break; + case 431: msg = QSE_MT("Request Header Fields Too Large"); break; + + case 500: msg = QSE_MT("Internal Server Error"); break; + case 501: msg = QSE_MT("Not Implemented"); break; + case 502: msg = QSE_MT("Bad Gateway"); break; + case 503: msg = QSE_MT("Service Unavailable"); break; + case 504: msg = QSE_MT("Gateway Timeout"); break; + case 505: msg = QSE_MT("HTTP Version Not Supported"); break; + + default: msg = QSE_MT("Unknown Error"); break; + } + + return msg; +} + const qse_mchar_t* qse_httpmethodtombs (qse_http_method_t type) { /* keep this table in the same order as qse_httpd_method_t enumerators */ @@ -410,3 +471,4 @@ qse_mchar_t* qse_perenchttpstrdup (const qse_mchar_t* str, qse_mmgr_t* mmgr) return buf; } + diff --git a/qse/lib/net/httpd-dir.c b/qse/lib/net/httpd-dir.c index 8253c713..db390822 100644 --- a/qse/lib/net/httpd-dir.c +++ b/qse/lib/net/httpd-dir.c @@ -22,7 +22,6 @@ #include "../cmn/mem.h" #include #include -#include #include /* TODO: remove this */ @@ -30,7 +29,6 @@ typedef struct task_dir_t task_dir_t; struct task_dir_t { qse_mcstr_t path; - qse_mcstr_t css; qse_mcstr_t qpath; qse_http_version_t version; int keepalive; @@ -44,7 +42,6 @@ struct task_dseg_t int chunked; qse_mcstr_t path; - qse_mcstr_t css; qse_mcstr_t qpath; qse_ubi_t handle; qse_httpd_dirent_t dent; @@ -59,13 +56,10 @@ struct task_dseg_t qse_size_t tcount; /* total directory entries */ qse_size_t dcount; /* the number of items in the buffer */ - qse_mchar_t tmbuf[128]; - qse_mchar_t fszbuf[128]; - - qse_mchar_t buf[4096]; - qse_size_t bufpos; - qse_size_t buflen; - qse_size_t bufrem; + qse_mchar_t buf[4096*2]; + int bufpos; + int buflen; + int bufrem; qse_size_t chunklen; }; @@ -79,9 +73,7 @@ static int task_init_dseg ( xtn->path.ptr = (qse_mchar_t*)(xtn + 1); qse_mbscpy ((qse_mchar_t*)xtn->path.ptr, arg->path.ptr); - xtn->css.ptr = xtn->path.ptr + xtn->path.len + 1; - qse_mbscpy ((qse_mchar_t*)xtn->css.ptr, arg->css.ptr); - xtn->qpath.ptr = xtn->css.ptr + xtn->css.len + 1; + xtn->qpath.ptr = xtn->path.ptr + xtn->path.len + 1; qse_mbscpy ((qse_mchar_t*)xtn->qpath.ptr, arg->qpath.ptr); task->ctx = xtn; @@ -135,35 +127,36 @@ static void fill_chunk_length (task_dseg_t* ctx) while (ctx->buf[ctx->bufpos] == QSE_MT(' ')) ctx->bufpos++; } -static int add_footer (task_dseg_t* ctx) +static int add_footer (qse_httpd_t* httpd, qse_httpd_client_t* client, task_dseg_t* ctx) { - int x; + int x, rem; - if (ctx->chunked) + rem = ctx->chunked? (ctx->buflen - 5): ctx->buflen; + if (rem < 1) { - x = snprintf ( - &ctx->buf[ctx->buflen], ctx->bufrem, - QSE_MT("\r\n0\r\n")); - } - else - { - x = snprintf ( - &ctx->buf[ctx->buflen], ctx->bufrem, - QSE_MT("")); - } - - if (x == -1 || x >= ctx->bufrem) - { - /* return an error if the buffer is too small to hold the - * trailing footer. you need to increate the buffer size */ + httpd->errnum = QSE_HTTPD_ENOBUF; return -1; } + x = httpd->rcb->format_dir ( + httpd, client, QSE_NULL, QSE_NULL, + &ctx->buf[ctx->buflen], rem); + if (x <= -1) return -1; + + QSE_ASSERT (x < rem); + ctx->buflen += x; ctx->bufrem -= x; - /* -5 for \r\n0\r\n added above */ - if (ctx->chunked) close_chunk_data (ctx, ctx->buflen - 5); + if (ctx->chunked) + { + qse_mbscpy (&ctx->buf[ctx->buflen], QSE_MT("\r\n0\r\n")); + ctx->buflen += 5; + ctx->bufrem -= 5; + + /* -5 for \r\n0\r\n added above */ + if (ctx->chunked) close_chunk_data (ctx, ctx->buflen - 5); + } return 0; } @@ -226,11 +219,10 @@ static int task_main_dseg ( if (ctx->state & FOOTER_PENDING) { /* only footers yet to be sent */ - if (add_footer (ctx) <= -1) + if (add_footer (httpd, client, ctx) <= -1) { /* return an error if the buffer is too small to hold the * trailing footer. you need to increate the buffer size */ - httpd->errnum = QSE_HTTPD_EINTERN; return -1; } @@ -243,31 +235,21 @@ static int task_main_dseg ( if (!(ctx->state & HEADER_ADDED)) { - int is_root; - - is_root = (qse_mbscmp (ctx->qpath.ptr, QSE_MT("/")) == 0); - /* compose the header since this is the first time. */ -/* TODO: page encoding?? utf-8??? or derive name from cmgr or current locale??? */ -/* TODO: html escaping of ctx->qpath.ptr */ - x = snprintf ( - &ctx->buf[ctx->buflen], ctx->bufrem, - QSE_MT("%s%s%s%s%s"), - (ctx->css.len > 0? QSE_MT(""): QSE_MT("")), - ctx->qpath.ptr, - (is_root? QSE_MT(""): QSE_MT("")) - ); - if (x == -1 || x >= ctx->bufrem) + x = httpd->rcb->format_dir ( + httpd, client, ctx->qpath.ptr, QSE_NULL, + &ctx->buf[ctx->buflen], ctx->bufrem); + if (x <= -1) { - /* return an error if the buffer is too small to hold the header. - * you need to increate the buffer size. or i have make the buffer - * dynamic. */ - httpd->errnum = QSE_HTTPD_EINTERN; + /* return an error if the buffer is too small to + * hold the header(httpd->errnum == QSE_HTTPD_ENOBUF). + * i need to increate the buffer size. or i have make + * the buffer dynamic. */ return -1; } + QSE_ASSERT (x < ctx->bufrem); + ctx->buflen += x; ctx->bufrem -= x; @@ -291,7 +273,7 @@ static int task_main_dseg ( { /* no more directory entry */ - if (add_footer (ctx) <= -1) + if (add_footer (httpd, client, ctx) <= -1) { /* failed to add the footer part */ if (ctx->chunked) @@ -309,52 +291,10 @@ static int task_main_dseg ( if (qse_mbscmp (ctx->dent.name, QSE_MT(".")) != 0 && qse_mbscmp (ctx->dent.name, QSE_MT("..")) != 0) { - qse_mchar_t* encname; - qse_btime_t bt; - - /* TODO: better buffer management in case there are - * a lot of file names to escape. */ - encname = qse_perenchttpstrdup (ctx->dent.name, httpd->mmgr); - if (encname == QSE_NULL) - { - httpd->errnum = QSE_HTTPD_ENOMEM; - return -1; - } - -qse_printf (QSE_T("ADDING [%hs]\n"), ctx->dent.name); - - qse_localtime (ctx->dent.stat.mtime, &bt); - snprintf (ctx->tmbuf, QSE_COUNTOF(ctx->tmbuf), - QSE_MT("%04d-%02d-%02d %02d:%02d:%02d"), - bt.year + QSE_BTIME_YEAR_BASE, bt.mon + 1, bt.mday, - bt.hour, bt.min, bt.sec); - - if (ctx->dent.stat.isdir) - { - ctx->fszbuf[0] = QSE_MT('\0'); - } - else - { - qse_fmtuintmaxtombs ( - ctx->fszbuf, QSE_COUNTOF(ctx->fszbuf), - ctx->dent.stat.size, 10, -1, QSE_MT('\0'), QSE_NULL - ); - } - - x = snprintf ( - &ctx->buf[ctx->buflen], - ctx->bufrem, - QSE_MT(""), - encname, - (ctx->dent.stat.isdir? QSE_MT("/"): QSE_MT("")), - ctx->dent.name, /* TODO: html escaping */ - (ctx->dent.stat.isdir? QSE_MT("/"): QSE_MT("")), - ctx->tmbuf, ctx->fszbuf - ); - - if (encname != ctx->dent.name) QSE_MMGR_FREE (httpd->mmgr, encname); - - if (x == -1 || x >= ctx->bufrem) + x = httpd->rcb->format_dir ( + httpd, client, ctx->qpath.ptr, &ctx->dent, + &ctx->buf[ctx->buflen], ctx->bufrem); + if (x <= -1) { /* buffer not large enough to hold this entry */ if (ctx->dcount <= 0) @@ -378,6 +318,8 @@ qse_printf (QSE_T("ADDING [%hs]\n"), ctx->dent.name); } else { + QSE_ASSERT (x < ctx->bufrem); + ctx->buflen += x; ctx->bufrem -= x; ctx->dcount++; @@ -416,7 +358,6 @@ static qse_httpd_task_t* entask_directory_segment ( data.keepalive = dir->keepalive; data.chunked = dir->keepalive; data.path = dir->path; - data.css = dir->css; data.qpath = dir->qpath; QSE_MEMSET (&task, 0, QSE_SIZEOF(task)); @@ -425,7 +366,7 @@ static qse_httpd_task_t* entask_directory_segment ( task.fini = task_fini_dseg; task.ctx = &data; - return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data) + data.path.len + 1 + data.css.len + 1 + data.qpath.len + 1); + return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data) + data.path.len + 1 + data.qpath.len + 1); } /*------------------------------------------------------------------------*/ @@ -441,9 +382,7 @@ static int task_init_dir ( xtn->path.ptr = (qse_mchar_t*)(xtn + 1); qse_mbscpy ((qse_mchar_t*)xtn->path.ptr, arg->path.ptr); - xtn->css.ptr = xtn->path.ptr + xtn->path.len + 1; - qse_mbscpy ((qse_mchar_t*)xtn->css.ptr, arg->css.ptr); - xtn->qpath.ptr = xtn->css.ptr + xtn->css.len + 1; + xtn->qpath.ptr = xtn->path.ptr + xtn->path.len + 1; qse_mbscpy ((qse_mchar_t*)xtn->qpath.ptr, arg->qpath.ptr); /* switch the context to the extension area */ @@ -495,15 +434,10 @@ static QSE_INLINE int task_main_dir ( } else { - x = qse_httpd_entaskformat ( - httpd, client, x, - QSE_MT("HTTP/%d.%d 301 Moved Permanently\r\nServer: %s\r\nDate: %s\r\nContent-Length: 0\r\nConnection: %s\r\nLocation: %s/\r\n\r\n"), - dir->version.major, dir->version.minor, - qse_httpd_getname (httpd), - qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0), - (dir->keepalive? QSE_MT("keep-alive"): QSE_MT("close")), - dir->qpath.ptr - ); + x = qse_httpd_entask_redir ( + httpd, client, x, dir->qpath.ptr, + &dir->version, dir->keepalive); + return (x == QSE_NULL)? -1: 0; } } @@ -513,19 +447,14 @@ qse_httpd_task_t* qse_httpd_entaskdir ( qse_httpd_client_t* client, qse_httpd_task_t* pred, const qse_mchar_t* path, - const qse_mchar_t* css, qse_htre_t* req) { qse_httpd_task_t task; task_dir_t data; - if (css == QSE_NULL) css = QSE_MT(""); - QSE_MEMSET (&data, 0, QSE_SIZEOF(data)); data.path.ptr = path; data.path.len = qse_mbslen(data.path.ptr); - data.css.ptr = css; - data.css.len = qse_mbslen(data.css.ptr); data.qpath.ptr = qse_htre_getqpath(req); data.qpath.len = qse_mbslen(data.qpath.ptr); data.version = *qse_htre_getversion(req); @@ -537,6 +466,6 @@ qse_httpd_task_t* qse_httpd_entaskdir ( task.ctx = &data; return qse_httpd_entask (httpd, client, pred, &task, - QSE_SIZEOF(task_dir_t) + data.path.len + 1 + data.css.len + 1 + data.qpath.len + 1); + QSE_SIZEOF(task_dir_t) + data.path.len + 1 + data.qpath.len + 1); } diff --git a/qse/lib/net/httpd-file.c b/qse/lib/net/httpd-file.c index 640d4dcc..3ba47aed 100644 --- a/qse/lib/net/httpd-file.c +++ b/qse/lib/net/httpd-file.c @@ -22,8 +22,6 @@ #include "../cmn/mem.h" #include #include -#include -#include #if defined(_WIN32) /* TODO: */ @@ -274,15 +272,7 @@ static QSE_INLINE int task_main_file ( /* i've converted milliseconds to seconds before timestamp comparison * because st.mtime has the actual milliseconds less than 1 second * while if_modified_since doesn't have such small milliseconds */ - - x = qse_httpd_entaskformat ( - httpd, client, x, - QSE_MT("HTTP/%d.%d 304 Not Modified\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Length: 0\r\n\r\n"), - file->version.major, file->version.minor, - qse_httpd_getname (httpd), - qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0), - (file->keepalive? QSE_MT("keep-alive"): QSE_MT("close")) - ); + x = qse_httpd_entask_nomod (httpd, client, x, &file->version, file->keepalive); goto no_file_send; } diff --git a/qse/lib/net/httpd-std.c b/qse/lib/net/httpd-std.c index 9b655780..adfd0608 100644 --- a/qse/lib/net/httpd-std.c +++ b/qse/lib/net/httpd-std.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #if defined(_WIN32) @@ -1584,6 +1585,125 @@ static int handle_request ( return process_request (httpd, client, req, 0); } +static int format_error ( + qse_httpd_t* httpd, qse_httpd_client_t* client, int code, qse_mchar_t* buf, int bufsz) +{ + int n; + server_xtn_t* server_xtn; + const qse_mchar_t* css, * msg; + + server_xtn = qse_httpd_getserverxtn (httpd, client->server); + + css = server_xtn->cfg[QSE_HTTPD_SERVER_XTN_CFG_ERRORCSS]; + if (!css) css = QSE_MT(""); + + msg = qse_httpstatustombs(code); + +/* TODO: use my own version of snprintf replacement */ + n = snprintf (buf, bufsz, + QSE_MT("%s%s
HTTP ERROR
%d %s
"), + css, msg, code, msg, qse_httpd_getname(httpd)); + if (n < 0 || n >= bufsz) + { + httpd->errnum = QSE_HTTPD_ENOBUF; + return -1; + } + + return n; +} + +static int format_dir ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + const qse_mchar_t* qpath, const qse_httpd_dirent_t* dirent, + qse_mchar_t* buf, int bufsz) +{ +/* TODO: page encoding?? utf-8??? or derive name from cmgr or current locale??? */ +/* TODO: html escaping of ctx->qpath.ptr */ + int n; + server_xtn_t* server_xtn; + + server_xtn = qse_httpd_getserverxtn (httpd, client->server); + + if (dirent == QSE_NULL) + { + if (qpath) + { + /* header */ + const qse_mchar_t* css; + int is_root = (qse_mbscmp (qpath, QSE_MT("/")) == 0); + + css = server_xtn->cfg[QSE_HTTPD_SERVER_XTN_CFG_DIRCSS]; + if (!css) css = QSE_MT(""); + +/* TODO: html escaping of qpath */ + n = snprintf (buf, bufsz, + QSE_MT("%s
%s
..
%s%s%s%s
%s"), css, qpath, + (is_root? QSE_MT(""): QSE_MT("")) + ); + } + else + { + /* footer */ + n = snprintf (buf, bufsz, QSE_MT("
..
"), qse_httpd_getname(httpd)); + } + } + else + { + /* main entry */ + qse_mchar_t* encname; + qse_btime_t bt; + qse_mchar_t tmbuf[32]; + qse_mchar_t fszbuf[64]; + + /* TODO: better buffer management in case there are + * a lot of file names to escape. */ + encname = qse_perenchttpstrdup (dirent->name, httpd->mmgr); + if (encname == QSE_NULL) + { + httpd->errnum = QSE_HTTPD_ENOMEM; + return -1; + } + + qse_localtime (dirent->stat.mtime, &bt); + snprintf (tmbuf, QSE_COUNTOF(tmbuf), + QSE_MT("%04d-%02d-%02d %02d:%02d:%02d"), + bt.year + QSE_BTIME_YEAR_BASE, bt.mon + 1, bt.mday, + bt.hour, bt.min, bt.sec); + + if (dirent->stat.isdir) + { + fszbuf[0] = QSE_MT('\0'); + } + else + { + qse_fmtuintmaxtombs ( + fszbuf, QSE_COUNTOF(fszbuf), + dirent->stat.size, 10, -1, QSE_MT('\0'), QSE_NULL + ); + } + + n = snprintf ( + buf, bufsz, + QSE_MT("%s%s%s%s"), + encname, + (dirent->stat.isdir? QSE_MT("/"): QSE_MT("")), + dirent->name, /* TODO: html escaping for entry name */ + (dirent->stat.isdir? QSE_MT("/"): QSE_MT("")), + tmbuf, fszbuf + ); + + if (encname != dirent->name) QSE_MMGR_FREE (httpd->mmgr, encname); + } + + if (n <= -1 || n >= bufsz) + { + httpd->errnum = QSE_HTTPD_ENOBUF; + return -1; + } + + return n; +} + static qse_httpd_scb_t httpd_system_callbacks = { /* server */ @@ -1638,7 +1758,9 @@ static qse_httpd_scb_t httpd_system_callbacks = static qse_httpd_rcb_t httpd_request_callbacks = { peek_request, - handle_request + handle_request, + format_error, + format_dir }; /* ------------------------------------------------------------------- */ @@ -1688,7 +1810,7 @@ static qse_mchar_t* merge_paths ( ta[idx++] = QSE_MT("/"); ta[idx++] = path; ta[idx++] = QSE_NULL; - xpath = qse_mbsadup (ta, httpd->mmgr); + xpath = qse_mbsadup (ta, QSE_NULL, httpd->mmgr); if (xpath == QSE_NULL) { httpd->errnum = QSE_HTTPD_ENOMEM; @@ -1796,8 +1918,8 @@ static int make_resource ( server_xtn = qse_httpd_getserverxtn (httpd, client->server); - if (server_xtn->cfg[SERVER_XTN_CFG_REALM].ptr && - server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].ptr) + if (server_xtn->cfg[SERVER_XTN_CFG_REALM] && + server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH]) { const qse_htre_hdrval_t* auth; @@ -1808,18 +1930,18 @@ static int make_resource ( if (qse_mbszcasecmp(auth->ptr, QSE_MT("Basic "), 6) == 0) { - if (qse_mbscmp (&auth->ptr[6], server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].ptr) == 0) goto auth_ok; + if (qse_mbscmp (&auth->ptr[6], server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH]) == 0) goto auth_ok; } } target->type = QSE_HTTPD_RSRC_AUTH; - target->u.auth.realm = server_xtn->cfg[SERVER_XTN_CFG_REALM].ptr; + target->u.auth.realm = server_xtn->cfg[SERVER_XTN_CFG_REALM]; return 0; } auth_ok: idxfile = QSE_NULL; - xpath = merge_paths (httpd, server_xtn->cfg[SERVER_XTN_CFG_DOCROOT].ptr, qpath); + xpath = merge_paths (httpd, server_xtn->cfg[SERVER_XTN_CFG_DOCROOT], qpath); if (xpath == QSE_NULL) return -1; if (QSE_STAT (xpath, &st) == 0 && S_ISDIR(st.st_mode)) @@ -1854,7 +1976,6 @@ auth_ok: target->type = QSE_HTTPD_RSRC_DIR; target->u.dir.path = xpath; - target->u.dir.css = server_xtn->cfg[SERVER_XTN_CFG_DIRCSS].ptr; } else { @@ -1862,7 +1983,7 @@ auth_ok: if (server_xtn->cgistd) { /* check if the request can resolve to a cgi script */ - n = attempt_cgi (httpd, server_xtn->cfg[SERVER_XTN_CFG_DOCROOT].ptr, + n = attempt_cgi (httpd, server_xtn->cfg[SERVER_XTN_CFG_DOCROOT], xpath, qpath, idxfile, server_xtn->cgistd, target); if (n <= -1) { @@ -1908,12 +2029,10 @@ static void predetach_server (qse_httpd_t* httpd, qse_httpd_server_t* server) for (i = QSE_COUNTOF(server_xtn->cfg); i > 0; ) { - i--; - if (server_xtn->cfg[i].ptr) + if (server_xtn->cfg[--i]) { - QSE_MMGR_FREE (httpd->mmgr, server_xtn->cfg[i].ptr); - server_xtn->cfg[i].ptr = QSE_NULL; - server_xtn->cfg[i].len = 0; + QSE_MMGR_FREE (httpd->mmgr, server_xtn->cfg[i]); + server_xtn->cfg[i] = QSE_NULL; } } } @@ -1925,11 +2044,11 @@ qse_httpd_server_t* qse_httpd_attachserverstd ( qse_httpd_server_t server; qse_httpd_server_t* xserver; server_xtn_t* server_xtn; - qse_mcstr_t tmp[4]; + const qse_mchar_t* tmp[4]; qse_mxstr_t ba; + qse_size_t balen2; qse_uint16_t default_port; - qse_size_t i; qse_uri_t xuri; static qse_httpd_server_cgistd_t server_cgistd[] = @@ -2007,49 +2126,36 @@ qse_httpd_server_t* qse_httpd_attachserverstd ( } #if defined(QSE_CHAR_IS_MCHAR) - server_xtn->cfg[SERVER_XTN_CFG_DOCROOT].ptr = qse_mbsxdup (xuri.path.ptr, xuri.path.len, httpd->mmgr); - if (xuri.path.ptr) server_xtn->cfg[SERVER_XTN_CFG_DOCROOT].ptr = qse_mbsxdup (xuri.path.ptr, xuri.path.len, httpd->mmgr); - if (xuri.auth.user.ptr) server_xtn->cfg[SERVER_XTN_CFG_USERNAME].ptr = qse_mbsxdup (xuri.auth.user.ptr, xuri.auth.user.len, httpd->mmgr); - if (xuri.auth.pass.ptr) server_xtn->cfg[SERVER_XTN_CFG_PASSWORD].ptr = qse_mbsxdup (xuri.auth.pass.ptr, xuri.auth.pass.len, httpd->mmgr); - if (xuri.frag.ptr) server_xtn->cfg[SERVER_XTN_CFG_REALM].ptr = qse_mbsxdup (xuri.frag.ptr, xuri.frag.len, httpd->mmgr); + server_xtn->cfg[SERVER_XTN_CFG_DOCROOT] = qse_mbsxdup (xuri.path.ptr, xuri.path.len, httpd->mmgr); + if (xuri.path.ptr) server_xtn->cfg[SERVER_XTN_CFG_DOCROOT] = qse_mbsxdup (xuri.path.ptr, xuri.path.len, httpd->mmgr); + if (xuri.auth.user.ptr) server_xtn->cfg[SERVER_XTN_CFG_USERNAME] = qse_mbsxdup (xuri.auth.user.ptr, xuri.auth.user.len, httpd->mmgr); + if (xuri.auth.pass.ptr) server_xtn->cfg[SERVER_XTN_CFG_PASSWORD] = qse_mbsxdup (xuri.auth.pass.ptr, xuri.auth.pass.len, httpd->mmgr); + if (xuri.frag.ptr) server_xtn->cfg[SERVER_XTN_CFG_REALM] = qse_mbsxdup (xuri.frag.ptr, xuri.frag.len, httpd->mmgr); #else - server_xtn->cfg[SERVER_XTN_CFG_DOCROOT].ptr = qse_wcsntombsdup (xuri.path.ptr, xuri.path.len, httpd->mmgr); - if (xuri.auth.user.ptr) server_xtn->cfg[SERVER_XTN_CFG_USERNAME].ptr = qse_wcsntombsdup (xuri.auth.user.ptr, xuri.auth.user.len, httpd->mmgr); - if (xuri.auth.pass.ptr) server_xtn->cfg[SERVER_XTN_CFG_PASSWORD].ptr = qse_wcsntombsdup (xuri.auth.pass.ptr, xuri.auth.pass.len, httpd->mmgr); - if (xuri.frag.ptr) server_xtn->cfg[SERVER_XTN_CFG_REALM].ptr = qse_wcsntombsdup (xuri.frag.ptr, xuri.frag.len, httpd->mmgr); + server_xtn->cfg[SERVER_XTN_CFG_DOCROOT] = qse_wcsntombsdup (xuri.path.ptr, xuri.path.len, httpd->mmgr); + if (xuri.auth.user.ptr) server_xtn->cfg[SERVER_XTN_CFG_USERNAME] = qse_wcsntombsdup (xuri.auth.user.ptr, xuri.auth.user.len, httpd->mmgr); + if (xuri.auth.pass.ptr) server_xtn->cfg[SERVER_XTN_CFG_PASSWORD] = qse_wcsntombsdup (xuri.auth.pass.ptr, xuri.auth.pass.len, httpd->mmgr); + if (xuri.frag.ptr) server_xtn->cfg[SERVER_XTN_CFG_REALM] = qse_wcsntombsdup (xuri.frag.ptr, xuri.frag.len, httpd->mmgr); #endif - if ((!server_xtn->cfg[SERVER_XTN_CFG_DOCROOT].ptr) || - (xuri.auth.user.ptr && !server_xtn->cfg[SERVER_XTN_CFG_USERNAME].ptr) || - (xuri.auth.pass.ptr && !server_xtn->cfg[SERVER_XTN_CFG_PASSWORD].ptr) || - (xuri.frag.ptr && !server_xtn->cfg[SERVER_XTN_CFG_REALM].ptr)) goto nomem_after_attach; + if ((!server_xtn->cfg[SERVER_XTN_CFG_DOCROOT]) || + (xuri.auth.user.ptr && !server_xtn->cfg[SERVER_XTN_CFG_USERNAME]) || + (xuri.auth.pass.ptr && !server_xtn->cfg[SERVER_XTN_CFG_PASSWORD]) || + (xuri.frag.ptr && !server_xtn->cfg[SERVER_XTN_CFG_REALM])) goto nomem_after_attach; - for (i = 0; i < QSE_COUNTOF(server_xtn->cfg); i++) - { - if (server_xtn->cfg[i].ptr) - server_xtn->cfg[i].len = qse_mbslen(server_xtn->cfg[i].ptr); - } + tmp[0] = server_xtn->cfg[SERVER_XTN_CFG_USERNAME]? server_xtn->cfg[SERVER_XTN_CFG_USERNAME]: QSE_MT(""); + tmp[1] = QSE_MT(":"); + tmp[2] = server_xtn->cfg[SERVER_XTN_CFG_PASSWORD]? server_xtn->cfg[SERVER_XTN_CFG_PASSWORD]: QSE_MT(""); + tmp[3] = QSE_NULL; - tmp[0].ptr = server_xtn->cfg[SERVER_XTN_CFG_USERNAME].ptr? server_xtn->cfg[SERVER_XTN_CFG_USERNAME].ptr: QSE_MT(""); - tmp[0].len = server_xtn->cfg[SERVER_XTN_CFG_USERNAME].len; - tmp[1].ptr = QSE_MT(":"); - tmp[1].len = 1; - tmp[2].ptr = server_xtn->cfg[SERVER_XTN_CFG_PASSWORD].ptr? server_xtn->cfg[SERVER_XTN_CFG_PASSWORD].ptr: QSE_MT(""); - tmp[2].len = server_xtn->cfg[SERVER_XTN_CFG_PASSWORD].len; - tmp[3].ptr = QSE_NULL; - tmp[3].len = 0; - - ba.ptr = qse_mbsxadup (tmp, httpd->mmgr); + ba.ptr = qse_mbsadup (tmp, &ba.len, httpd->mmgr); if (!ba.ptr) goto nomem_after_attach; - ba.len = tmp[0].len + tmp[1].len + tmp[2].len; - server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].len = ((ba.len / 3) + 1) * 4; - server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].ptr = QSE_MMGR_ALLOC ( - httpd->mmgr, - (server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].len + 1) * QSE_SIZEOF(qse_mchar_t) - ); - if (!server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].ptr) + balen2 = ((ba.len / 3) + 1) * 4; + server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH] = QSE_MMGR_ALLOC ( + httpd->mmgr, (balen2 + 1) * QSE_SIZEOF(qse_mchar_t)); + if (!server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH]) { QSE_MMGR_FREE (httpd->mmgr, ba.ptr); goto nomem_after_attach; @@ -2057,12 +2163,12 @@ qse_httpd_server_t* qse_httpd_attachserverstd ( qse_enbase64 ( ba.ptr, ba.len, - server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].ptr, - server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].len, - &server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].len + server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH], + balen2, + &balen2 ); QSE_MMGR_FREE (httpd->mmgr, ba.ptr); - server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].ptr[server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH].len] = QSE_MT('\0'); + (server_xtn->cfg[SERVER_XTN_CFG_BASICAUTH])[balen2] = QSE_MT('\0'); server_xtn->predetach = predetach; server_xtn->cbstd = &server_cbstd; diff --git a/qse/lib/net/httpd-task.c b/qse/lib/net/httpd-task.c index d6d2b664..5a20405c 100644 --- a/qse/lib/net/httpd-task.c +++ b/qse/lib/net/httpd-task.c @@ -205,96 +205,76 @@ qse_printf (QSE_T("SEND: [%.*hs]\n"), (int)l, buf); /*------------------------------------------------------------------------*/ -qse_httpd_task_t* qse_httpd_entask_error ( +typedef struct status_reloc_t status_reloc_t; +struct status_reloc_t +{ + const qse_mchar_t* dst; + int redir; +}; + +static qse_httpd_task_t* entask_status ( qse_httpd_t* httpd, qse_httpd_client_t* client, - qse_httpd_task_t* pred, int code, + qse_httpd_task_t* pred, int code, void* extra, const qse_http_version_t* version, int keepalive) { - const qse_mchar_t* smsg; - const qse_mchar_t* lmsg; + const qse_mchar_t* msg; - switch (code) + const qse_mchar_t* extrapre = QSE_MT(""); + const qse_mchar_t* extrapst = QSE_MT(""); + const qse_mchar_t* extraval = QSE_MT(""); + + qse_mchar_t text[1024] = QSE_MT(""); /* TODO: make this buffer dynamic or scalable */ + + msg = qse_httpstatustombs (code); + if (code == 301 || code == 307) { - case 403: - smsg = QSE_MT("Forbidden"); - lmsg = QSE_MT("ForbiddenFORBIDDEN"); - break; - - case 404: - smsg = QSE_MT("Not Found"); - lmsg = QSE_MT("Not FoundREQUESTED PATH NOT FOUND"); - break; - - case 405: - smsg = QSE_MT("Method Not Allowed"); - lmsg = QSE_MT("Method Not AllowedREQUESTED METHOD NOT ALLOWED"); - break; - - case 411: - smsg = QSE_MT("Length Required"); - lmsg = QSE_MT("Length RequiredLENGTH REQUIRED"); - break; - - case 416: - smsg = QSE_MT("Requested Range Not Satisfiable"); - lmsg = QSE_MT("Requested Range Not SatsfiableREQUESTED RANGE NOT SATISFIABLE"); - break; - - case 417: - smsg = QSE_MT("Expectation Failed"); - lmsg = QSE_MT("Expectation FailedEXPECTATION FAILED"); - break; - - case 500: - smsg = QSE_MT("Internal Server Error"); - lmsg = QSE_MT("Internal Server ErrorINTERNAL SERVER ERROR"); - break; - - case 501: - smsg = QSE_MT("Not Implemented"); - lmsg = QSE_MT("Not ImplementedNOT IMPLEMENTED"); - break; - - case 502: - smsg = QSE_MT("Bad Gateway"); - lmsg = QSE_MT("Bad GatewayBAD GATEWAY"); - break; - - case 503: - smsg = QSE_MT("Service Unavailable"); - lmsg = QSE_MT("Service UnavailableSERVICE UNAVAILABLE"); - break; - - case 504: - smsg = QSE_MT("Gateway Timeout"); - lmsg = QSE_MT("Gateway TimeoutGATEWAY TIMEOUT"); - break; - - default: - smsg = QSE_MT("Unknown"); - lmsg = QSE_MT("Unknown ErrorUNKNOWN ERROR"); - break; + status_reloc_t* reloc = (status_reloc_t*)extra; + extrapre = QSE_MT("Location: "); + extrapst = reloc->redir? QSE_MT("/\r\n"): QSE_MT("\r\n"); + extraval = reloc->dst; + } + else if (code == 304) + { + /* nothing to do */ + } + else + { + if (httpd->rcb->format_error (httpd, client, code, text, QSE_COUNTOF(text)) <= -1) return -1; + if (code == 401) + { + extrapre = QSE_MT("WWW-Authenticate: Basic realm=\""); + extrapst = QSE_MT("\"\r\n"); + extraval = (const qse_mchar_t*)extra; + } } return qse_httpd_entaskformat ( httpd, client, pred, - QSE_MT("HTTP/%d.%d %d %s\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: text/html\r\nContent-Length: %lu\r\n\r\n%s\r\n\r\n"), - version->major, version->minor, code, smsg, - qse_httpd_getname (httpd), + QSE_MT("HTTP/%d.%d %d %s\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: text/html\r\nContent-Length: %lu\r\n%s%s%s\r\n%s"), + version->major, version->minor, + code, msg, qse_httpd_getname (httpd), qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0), (keepalive? QSE_MT("keep-alive"): QSE_MT("close")), - (unsigned long)qse_mbslen(lmsg) + 4, lmsg - ); + (unsigned long)qse_mbslen(text), + extrapre, extraval, extrapst, text); +} +/*------------------------------------------------------------------------*/ + +qse_httpd_task_t* qse_httpd_entask_error ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + qse_httpd_task_t* pred, int code, + const qse_http_version_t* version, int keepalive) +{ + return entask_status (httpd, client, pred, code, QSE_NULL, version, keepalive); } 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) { - return qse_httpd_entask_error ( - httpd, client, pred, code, - qse_htre_getversion(req), - (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)); + return entask_status ( + httpd, client, pred, code, QSE_NULL, + qse_htre_getversion(req), (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)); } /*------------------------------------------------------------------------*/ @@ -315,40 +295,94 @@ qse_httpd_task_t* qse_httpd_entaskauth ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* pred, const qse_mchar_t* realm, qse_htre_t* req) { - const qse_http_version_t* version; - const qse_mchar_t* lmsg; - - version = qse_htre_getversion(req); - lmsg = QSE_MT("UnauthorizedUNAUTHORIZED"); - - return qse_httpd_entaskformat ( - httpd, client, pred, - QSE_MT("HTTP/%d.%d 401 Unauthorized\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nWWW-Authenticate: Basic realm=\"%s\"\r\nContent-Type: text/html\r\nContent-Length: %lu\r\n\r\n%s\r\n\r\n"), - version->major, version->minor, - qse_httpd_getname (httpd), - qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0), - ((req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)? QSE_MT("keep-alive"): QSE_MT("close")), - realm, (unsigned long)qse_mbslen(lmsg) + 4, lmsg); + return entask_status ( + httpd, client, pred, 401, (void*)realm, + qse_htre_getversion(req), + (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)); } + /*------------------------------------------------------------------------*/ +qse_httpd_task_t* qse_httpd_entask_reloc ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + qse_httpd_task_t* pred, const qse_mchar_t* dst, + const qse_http_version_t* version, int keepalive) +{ + status_reloc_t reloc; + + reloc.dst = dst; + reloc.redir = 0; + + return entask_status ( + httpd, client, pred, 301, (void*)&reloc, + version, keepalive); +} + qse_httpd_task_t* qse_httpd_entaskreloc ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* pred, const qse_mchar_t* dst, qse_htre_t* req) { - const qse_http_version_t* version; + status_reloc_t reloc; - version = qse_htre_getversion(req); + reloc.dst = dst; + reloc.redir = 0; - return qse_httpd_entaskformat ( - httpd, client, pred, - QSE_MT("HTTP/%d.%d 301 Moved Permanently\r\nServer: %s\r\nDate: %s\r\nContent-Length: 0\r\nConnection: %s\r\nLocation: %s\r\n\r\n"), - version->major, version->minor, - qse_httpd_getname (httpd), - qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0), - ((req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)? QSE_MT("keep-alive"): QSE_MT("close")), - dst); + return entask_status ( + httpd, client, pred, 301, (void*)&reloc, + qse_htre_getversion(req), + (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)); +} + +qse_httpd_task_t* qse_httpd_entask_redir ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + qse_httpd_task_t* pred, const qse_mchar_t* dst, + const qse_http_version_t* version, int keepalive) +{ + status_reloc_t reloc; + + reloc.dst = dst; + reloc.redir = 1; + + return entask_status ( + httpd, client, pred, 301, (void*)&reloc, + version, keepalive); +} + +qse_httpd_task_t* qse_httpd_entaskredir ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + qse_httpd_task_t* pred, const qse_mchar_t* dst, qse_htre_t* req) +{ + status_reloc_t reloc; + + reloc.dst = dst; + reloc.redir = 1; + + return entask_status ( + httpd, client, pred, 301, (void*)&reloc, + qse_htre_getversion(req), + (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)); +} + +/*------------------------------------------------------------------------*/ + +qse_httpd_task_t* qse_httpd_entask_nomod ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + qse_httpd_task_t* pred, const qse_http_version_t* version, int keepalive) +{ + return entask_status ( + httpd, client, pred, 304, + QSE_NULL, version, keepalive); +} + +qse_httpd_task_t* qse_httpd_entasknomod ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + qse_httpd_task_t* pred, qse_htre_t* req) +{ + return entask_status ( + httpd, client, pred, 304, + QSE_NULL, qse_htre_getversion(req), + (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)); } /*------------------------------------------------------------------------*/ @@ -390,7 +424,7 @@ qse_httpd_task_t* qse_httpd_entaskrsrc ( case QSE_HTTPD_RSRC_DIR: qse_httpd_discardcontent (httpd, req); - task = qse_httpd_entaskdir (httpd, client, QSE_NULL, rsrc->u.dir.path, rsrc->u.dir.css, req); + task = qse_httpd_entaskdir (httpd, client, QSE_NULL, rsrc->u.dir.path, req); break; case QSE_HTTPD_RSRC_ERROR: @@ -411,6 +445,10 @@ qse_httpd_task_t* qse_httpd_entaskrsrc ( task = qse_httpd_entaskreloc (httpd, client, QSE_NULL, rsrc->u.reloc.dst, req); break; + case QSE_HTTPD_RSRC_REDIR: + task = qse_httpd_entaskredir (httpd, client, QSE_NULL, rsrc->u.redir.dst, req); + break; + case QSE_HTTPD_RSRC_TEXT: task = qse_httpd_entasktext (httpd, client, QSE_NULL, rsrc->u.text.ptr, rsrc->u.text.mime, req); break; diff --git a/qse/lib/net/httpd.h b/qse/lib/net/httpd.h index 1a91b7ab..a30598b2 100644 --- a/qse/lib/net/httpd.h +++ b/qse/lib/net/httpd.h @@ -110,6 +110,33 @@ qse_httpd_task_t* qse_httpd_entask_error ( int keepalive ); +qse_httpd_task_t* qse_httpd_entask_nomod ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_httpd_task_t* pred, + const qse_http_version_t* version, + int keepalive +); + +qse_httpd_task_t* qse_httpd_entask_reloc ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_httpd_task_t* pred, + const qse_mchar_t* dst, + const qse_http_version_t* version, + int keepalive +); + +qse_httpd_task_t* qse_httpd_entask_redir ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_httpd_task_t* pred, + const qse_mchar_t* dst, + const qse_http_version_t* version, + int keepalive +); + + qse_httpd_task_t* qse_httpd_entask_text ( qse_httpd_t* httpd, qse_httpd_client_t* client, diff --git a/qse/samples/net/httpd01.c b/qse/samples/net/httpd01.c index 8b6e75a9..0724c158 100644 --- a/qse/samples/net/httpd01.c +++ b/qse/samples/net/httpd01.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -71,8 +70,12 @@ static int httpd_main (int argc, qse_char_t* argv[]) } server_xtn = qse_httpd_getserverxtn (httpd, server); - server_xtn->cfg[QSE_HTTPD_SERVER_XTN_CFG_DIRCSS].ptr = QSE_MT("body { background-color:#d0e4fe; font-size: 0.9em; font-family: Ubuntu,'Trebuchet MS',sans-serif; }"); - server_xtn->cfg[QSE_HTTPD_SERVER_XTN_CFG_DIRCSS].len = qse_mbslen(server_xtn->cfg[QSE_HTTPD_SERVER_XTN_CFG_DIRCSS].ptr); + /* don't care about failure */ + server_xtn->cfg[QSE_HTTPD_SERVER_XTN_CFG_DIRCSS] = + qse_mbsdup (QSE_MT(""), qse_httpd_getmmgr(httpd)); + + server_xtn->cfg[QSE_HTTPD_SERVER_XTN_CFG_ERRORCSS] = + qse_mbsdup (QSE_MT(""), qse_httpd_getmmgr(httpd)); } g_httpd = httpd;