From cb34385dedf62dc4832f23b514595552cf04f4a5 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Tue, 25 Sep 2012 02:47:25 +0000 Subject: [PATCH] fixed a formatting bug in qse_strtonwad() renamed qse_httpd_addserver() to qse_httpd_attachserver(). added qse_httpd_detachserver(). added the predetach field to qse_httpd_server_t. added qse_httpd_cbstd_t and changed qse_htpd_loopstd() to accept this cbstd. enhanced server uri parsing to include 'docroot'. enhanced qse_httpd_entasktext() and added qse_httpd_entask_text() for internal use. added nwif functions like qse_nwifindextombs(). added qse_env_insertmbsa()/qse_env_insertwcsa()/qse_env_inserta(). enhanced TPROXY handling --- qse/configure | 9 +- qse/configure.ac | 2 +- qse/include/qse/cmn/Makefile.am | 1 + qse/include/qse/cmn/Makefile.in | 13 +- qse/include/qse/cmn/env.h | 22 +- qse/include/qse/cmn/gdl.h | 12 +- qse/include/qse/cmn/nwif.h | 75 ++++ qse/include/qse/config.h.in | 3 + qse/include/qse/net/httpd.h | 185 +++++++--- qse/lib/cmn/Makefile.am | 1 + qse/lib/cmn/Makefile.in | 23 +- qse/lib/cmn/env.c | 85 +++-- qse/lib/cmn/nwad.c | 134 ++----- qse/lib/cmn/nwif.c | 296 +++++++++++++++ qse/lib/net/Makefile.am | 1 + qse/lib/net/Makefile.in | 5 +- qse/lib/net/httpd-cgi.c | 33 +- qse/lib/net/httpd-dir.c | 51 ++- qse/lib/net/httpd-file.c | 54 ++- qse/lib/net/httpd-proxy.c | 16 +- qse/lib/net/httpd-std.c | 633 ++++++++++++++++++++++---------- qse/lib/net/httpd-task.c | 186 ++++------ qse/lib/net/httpd-text.c | 120 ++++++ qse/lib/net/httpd.c | 169 ++++----- qse/lib/net/httpd.h | 14 +- qse/samples/cmn/nwad01.c | 3 +- qse/samples/net/httpd01.c | 2 +- qse/samples/net/httpd02.c | 133 +------ 28 files changed, 1466 insertions(+), 815 deletions(-) create mode 100644 qse/include/qse/cmn/nwif.h create mode 100644 qse/lib/cmn/nwif.c create mode 100644 qse/lib/net/httpd-text.c diff --git a/qse/configure b/qse/configure index 7c30e813..d21f2f64 100755 --- a/qse/configure +++ b/qse/configure @@ -16096,12 +16096,13 @@ fi done -for ac_header in net/if.h +for ac_header in sys/ioctl.h net/if.h do : - ac_fn_c_check_header_mongrel "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "$ac_includes_default" -if test "x$ac_cv_header_net_if_h" = xyes; then : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF -#define HAVE_NET_IF_H 1 +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi diff --git a/qse/configure.ac b/qse/configure.ac index ded6543f..2729cb4e 100644 --- a/qse/configure.ac +++ b/qse/configure.ac @@ -85,7 +85,7 @@ AC_HEADER_STDC AC_CHECK_HEADERS([stddef.h wchar.h wctype.h errno.h signal.h fcntl.h dirent.h]) AC_CHECK_HEADERS([time.h sys/time.h utime.h spawn.h execinfo.h]) AC_CHECK_HEADERS([sys/resource.h sys/wait.h sys/syscall.h sys/sendfile.h sys/epoll.h]) -AC_CHECK_HEADERS([net/if.h]) +AC_CHECK_HEADERS([sys/ioctl.h net/if.h]) dnl check data types AC_CHECK_TYPE([wchar_t], diff --git a/qse/include/qse/cmn/Makefile.am b/qse/include/qse/cmn/Makefile.am index 3fb8802f..1d45c208 100644 --- a/qse/include/qse/cmn/Makefile.am +++ b/qse/include/qse/cmn/Makefile.am @@ -22,6 +22,7 @@ pkginclude_HEADERS = \ mbwc.h \ mem.h \ nwad.h \ + nwif.h \ nwio.h \ oht.h \ opt.h \ diff --git a/qse/include/qse/cmn/Makefile.in b/qse/include/qse/cmn/Makefile.in index d7efbf93..68fb1134 100644 --- a/qse/include/qse/cmn/Makefile.in +++ b/qse/include/qse/cmn/Makefile.in @@ -53,9 +53,10 @@ SOURCES = DIST_SOURCES = am__pkginclude_HEADERS_DIST = alg.h chr.h cp949.h cp950.h dll.h env.h \ fio.h fma.h fmt.h fs.h gdl.h glob.h htb.h hton.h ipad.h lda.h \ - main.h map.h mbwc.h mem.h nwad.h nwio.h oht.h opt.h path.h \ - pio.h pma.h rbt.h rex.h sio.h sll.h slmb.h stdio.h str.h \ - time.h tio.h tre.h utf8.h xma.h Mmgr.hpp StdMmgr.hpp Mmged.hpp + main.h map.h mbwc.h mem.h nwad.h nwif.h nwio.h oht.h opt.h \ + path.h pio.h pma.h rbt.h rex.h sio.h sll.h slmb.h stdio.h \ + str.h time.h tio.h tre.h utf8.h xma.h Mmgr.hpp StdMmgr.hpp \ + Mmged.hpp am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ @@ -244,9 +245,9 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ pkginclude_HEADERS = alg.h chr.h cp949.h cp950.h dll.h env.h fio.h \ fma.h fmt.h fs.h gdl.h glob.h htb.h hton.h ipad.h lda.h main.h \ - map.h mbwc.h mem.h nwad.h nwio.h oht.h opt.h path.h pio.h \ - pma.h rbt.h rex.h sio.h sll.h slmb.h stdio.h str.h time.h \ - tio.h tre.h utf8.h xma.h $(am__append_1) + map.h mbwc.h mem.h nwad.h nwif.h nwio.h oht.h opt.h path.h \ + pio.h pma.h rbt.h rex.h sio.h sll.h slmb.h stdio.h str.h \ + time.h tio.h tre.h utf8.h xma.h $(am__append_1) all: all-am .SUFFIXES: diff --git a/qse/include/qse/cmn/env.h b/qse/include/qse/cmn/env.h index 496f2544..70ffa711 100644 --- a/qse/include/qse/cmn/env.h +++ b/qse/include/qse/cmn/env.h @@ -119,12 +119,24 @@ int qse_env_insertwcs ( const qse_wchar_t* value ); +int qse_env_insertwcsa ( + qse_env_t* env, + const qse_wchar_t* name, + const qse_wchar_t* value[] +); + int qse_env_insertmbs ( qse_env_t* env, const qse_mchar_t* name, const qse_mchar_t* value ); +int qse_env_insertmbsa ( + qse_env_t* env, + const qse_mchar_t* name, + const qse_mchar_t* value[] +); + int qse_env_deletewcs ( qse_env_t* env, const qse_wchar_t* name @@ -135,12 +147,14 @@ int qse_env_deletembs ( const qse_mchar_t* name ); -#if defined(QSE_CHAR_IS_WCHAR) -# define qse_env_insert(env,name,value) qse_env_insertwcs(env,name,value) -# define qse_env_delete(env,name) qse_env_deletewcs(env,name) -#else +#if defined(QSE_CHAR_IS_MCHAR) # define qse_env_insert(env,name,value) qse_env_insertmbs(env,name,value) +# define qse_env_inserta(env,name,value) qse_env_insertmbsa(env,name,value) # define qse_env_delete(env,name) qse_env_deletembs(env,name) +#else +# define qse_env_insert(env,name,value) qse_env_insertwcs(env,name,value) +# define qse_env_inserta(env,name,value) qse_env_insertwcsa(env,name,value) +# define qse_env_delete(env,name) qse_env_deletewcs(env,name) #endif #ifdef __cplusplus diff --git a/qse/include/qse/cmn/gdl.h b/qse/include/qse/cmn/gdl.h index eccc0d62..2023bb04 100644 --- a/qse/include/qse/cmn/gdl.h +++ b/qse/include/qse/cmn/gdl.h @@ -38,11 +38,11 @@ struct qse_gdl_t }; /** - * The QSE_GDL_INIT macro initializes a host link to be used for internal + * The QSE_GDL_INIT macro initializes a link to be used for internal * management. */ -#define QSE_GDL_INIT(host) QSE_BLOCK ( \ - (host)->next = (host); (host)->prev = (host); \ +#define QSE_GDL_INIT(link) QSE_BLOCK ( \ + (link)->next = (link); (link)->prev = (link); \ ) /** @@ -59,17 +59,17 @@ struct qse_gdl_t /** * The QSE_GDL_ISEMPTY macro checks if the chain is empty. */ -#define QSE_GDL_ISEMPTY(host) ((host)->next == (host)) +#define QSE_GDL_ISEMPTY(link) ((link)->next == (link)) /** * The QSE_GDL_HEAD macro get the first node in the chain. */ -#define QSE_GDL_HEAD(host) ((host)->next) +#define QSE_GDL_HEAD(link) ((link)->next) /** * The QSE_GDL_TAIL macro gets the last node in the chain. */ -#define QSE_GDL_TAIL(host) ((host)->prev) +#define QSE_GDL_TAIL(link) ((link)->prev) #ifdef __cplusplus extern "C" { diff --git a/qse/include/qse/cmn/nwif.h b/qse/include/qse/cmn/nwif.h new file mode 100644 index 00000000..ee23b060 --- /dev/null +++ b/qse/include/qse/cmn/nwif.h @@ -0,0 +1,75 @@ +/* + * $Id$ + * + Copyright 2006-2012 Chung, Hyung-Hwan. + This file is part of QSE. + + QSE is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + QSE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with QSE. If not, see . + */ + +#ifndef _QSE_CMN_NWIF_H_ +#define _QSE_CMN_NWIF_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +unsigned int qse_nwifmbstoindex ( + const qse_mchar_t* ptr +); + +unsigned int qse_nwifwcstoindex ( + const qse_wchar_t* ptr +); + +unsigned int qse_nwifmbsntoindex ( + const qse_mchar_t* ptr, + qse_size_t len +); + +unsigned int qse_nwifwcsntoindex ( + const qse_wchar_t* ptr, + qse_size_t len +); + +qse_size_t qse_nwifindextombs ( + unsigned int index, + qse_mchar_t* buf, + qse_size_t len +); + +qse_size_t qse_nwifindextowcs ( + unsigned int index, + qse_wchar_t* buf, + qse_size_t len +); + +#if defined(QSE_CHAR_IS_MCHAR) +# define qse_nwifstrtoindex(ptr) qse_nwifmbstoindex(ptr) +# define qse_nwifstrntoindex(ptr,len) qse_nwifmbsntoindex(ptr,len) +# define qse_nwifindextostr(index,buf,len) qse_nwifindextombs(index,buf,len) +#else +# define qse_nwifstrtoindex(ptr) qse_nwifwcstoindex(ptr) +# define qse_nwifstrntoindex(ptr,len) qse_nwifwcsntoindex(ptr,len) +# define qse_nwifindextostr(index,buf,len) qse_nwifindextowcs(index,buf,len) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/qse/include/qse/config.h.in b/qse/include/qse/config.h.in index 69d453b6..3e384ae2 100644 --- a/qse/include/qse/config.h.in +++ b/qse/include/qse/config.h.in @@ -299,6 +299,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_EPOLL_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H diff --git a/qse/include/qse/net/httpd.h b/qse/include/qse/net/httpd.h index 6b05d60b..9a2cdc84 100644 --- a/qse/include/qse/net/httpd.h +++ b/qse/include/qse/net/httpd.h @@ -69,26 +69,37 @@ struct qse_httpd_stat_t qse_long_t ino; qse_foff_t size; qse_ntime_t mtime; - const qse_mchar_t* mime; +}; + +enum qse_httpd_server_flag_t +{ + QSE_HTTPD_SERVER_ACTIVE = (1 << 0), + QSE_HTTPD_SERVER_SECURE = (1 << 1), + QSE_HTTPD_SERVER_BINDTONWIF = (1 << 2) }; typedef struct qse_httpd_server_t qse_httpd_server_t; struct qse_httpd_server_t { - qse_httpd_server_t* next; - int active; - - qse_nwad_t nwad; - int secure; + /* ---------------------------------------------- */ + int flags; + qse_nwad_t nwad; /* binding address */ + unsigned int nwif; /* interface number to bind to */ + void (*predetach) (qse_httpd_t*, qse_httpd_server_t*); /* set by server.open callback */ qse_ubi_t handle; + + /* private */ + qse_httpd_server_t* next; + qse_httpd_server_t* prev; }; typedef struct qse_httpd_peer_t qse_httpd_peer_t; struct qse_httpd_peer_t { qse_nwad_t nwad; + qse_nwad_t local; /* local side address facing the peer */ qse_ubi_t handle; }; @@ -285,6 +296,8 @@ struct qse_httpd_client_t qse_nwad_t remote_addr; qse_nwad_t local_addr; qse_nwad_t orgdst_addr; + qse_httpd_server_t* server; + int initial_ifindex; /* == PRIVATE == */ qse_htrd_t* htrd; @@ -308,6 +321,73 @@ struct qse_httpd_client_t } task; }; +/** + * The qse_httpd_rsrc_type_t defines the resource type than can + * be entasked with qse_httpd_entaskrsrc(). + */ +enum qse_httpd_rsrc_type_t +{ + QSE_HTTPD_RSRC_AUTH, + QSE_HTTPD_RSRC_CGI, + QSE_HTTPD_RSRC_DIR, + QSE_HTTPD_RSRC_ERROR, + QSE_HTTPD_RSRC_FILE, + QSE_HTTPD_RSRC_PROXY, + QSE_HTTPD_RSRC_RELOC, + QSE_HTTPD_RSRC_TEXT +}; +typedef enum qse_httpd_rsrc_type_t qse_httpd_rsrc_type_t; + +typedef struct qse_httpd_rsrc_t qse_httpd_rsrc_t; + +struct qse_httpd_rsrc_t +{ + qse_httpd_rsrc_type_t type; + union + { + struct + { + const qse_mchar_t* realm; + } auth; + struct + { + const qse_mchar_t* path; + const qse_mchar_t* script; + const qse_mchar_t* suffix; + const qse_mchar_t* docroot; + int nph; + } cgi; + struct + { + const qse_mchar_t* path; + } dir; + + int error; + + struct + { + const qse_mchar_t* path; + const qse_mchar_t* mime; + } file; + + struct + { + qse_nwad_t dst; + qse_nwad_t src; + } proxy; + struct + { + const qse_mchar_t* dst; + } reloc; + + struct + { + const qse_mchar_t* ptr; + const qse_mchar_t* mime; + } text; + } u; +}; + /** * The qse_httpd_ecb_close_t type defines the callback function * called when an httpd object is closed. @@ -335,6 +415,13 @@ struct qse_httpd_ecb_t }; +typedef struct qse_httpd_cbstd_t qse_httpd_cbstd_t; +struct qse_httpd_cbstd_t +{ + int (*makersrc) (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, qse_httpd_rsrc_t* rsrc); /* required */ + void (*freersrc) (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, qse_httpd_rsrc_t* rsrc); /* optional */ +}; + #ifdef __cplusplus extern "C" { #endif @@ -408,9 +495,17 @@ void qse_httpd_stop ( qse_httpd_t* httpd ); -int qse_httpd_addserver ( - qse_httpd_t* httpd, - const qse_char_t* uri +#define qse_httpd_getserverxtn(httpd,server) ((void*)(server+1)) + +qse_httpd_server_t* qse_httpd_attachserver ( + qse_httpd_t* httpd, + const qse_httpd_server_t* tmpl, + qse_size_t xtnsize +); + +void qse_httpd_detachserver ( + qse_httpd_t* httpd, + qse_httpd_server_t* server ); void qse_httpd_discardcontent ( @@ -424,7 +519,6 @@ void qse_httpd_completecontent ( ); - /** * The qse_httpd_setname() function changes the string * to be used as the value for the server header. @@ -473,19 +567,6 @@ qse_httpd_task_t* qse_httpd_entaskdisconnect ( qse_httpd_task_t* pred ); -qse_httpd_task_t* qse_httpd_entasktext ( - qse_httpd_t* httpd, - qse_httpd_client_t* client, - qse_httpd_task_t* pred, - const qse_mchar_t* text -); - -qse_httpd_task_t* qse_httpd_entaskstatictext ( - qse_httpd_t* httpd, - qse_httpd_client_t* client, - qse_httpd_task_t* pred, - const qse_mchar_t* text -); qse_httpd_task_t* qse_httpd_entaskformat ( qse_httpd_t* httpd, @@ -497,6 +578,15 @@ qse_httpd_task_t* qse_httpd_entaskformat ( /* -------------------------------------------- */ +qse_httpd_task_t* qse_httpd_entasktext ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_httpd_task_t* pred, + const qse_mchar_t* text, + const qse_mchar_t* mime, + qse_htre_t* req +); + qse_httpd_task_t* qse_httpd_entaskerror ( qse_httpd_t* httpd, qse_httpd_client_t* client, @@ -523,6 +613,14 @@ qse_httpd_task_t* qse_httpd_entaskauth ( qse_htre_t* req ); +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 +); + qse_httpd_task_t* qse_httpd_entaskdir ( qse_httpd_t* httpd, qse_httpd_client_t* client, @@ -536,20 +634,7 @@ qse_httpd_task_t* qse_httpd_entaskfile ( qse_httpd_client_t* client, qse_httpd_task_t* pred, const qse_mchar_t* name, - qse_htre_t* req -); - -/** - * The qse_httpd_entaskphat() functions a dispatcher between - * qse_httpd_entaskdir() and qse_httpd_entaskfile(). It calls - * the former if @a name is a directory and calls the latter - * otherwise. - */ -qse_httpd_task_t* qse_httpd_entaskpath ( - qse_httpd_t* httpd, - qse_httpd_client_t* client, - qse_httpd_task_t* pred, - const qse_mchar_t* name, + const qse_mchar_t* mime, qse_htre_t* req ); @@ -560,6 +645,7 @@ qse_httpd_task_t* qse_httpd_entaskcgi ( const qse_mchar_t* path, const qse_mchar_t* script, const qse_mchar_t* suffix, + const qse_mchar_t* docroot, int nph, qse_htre_t* req ); @@ -568,7 +654,18 @@ qse_httpd_task_t* qse_httpd_entaskproxy ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* pred, - const qse_nwad_t* nwad, + const qse_nwad_t* dst, + const qse_nwad_t* src, + qse_htre_t* req +); + +/* -------------------------------------------- */ + +qse_httpd_task_t* qse_httpd_entaskrsrc ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_httpd_task_t* pred, + qse_httpd_rsrc_t* rsrc, qse_htre_t* req ); @@ -606,10 +703,16 @@ void* qse_httpd_getxtnstd ( qse_httpd_t* httpd ); +qse_httpd_server_t* qse_httpd_attachserverstd ( + qse_httpd_t* httpd, + const qse_char_t* uri, + qse_size_t xtnsize +); + int qse_httpd_loopstd ( - qse_httpd_t* httpd, - qse_httpd_rcb_t* rcb, - qse_ntime_t timeout + qse_httpd_t* httpd, + qse_httpd_cbstd_t* cbstd, + qse_ntime_t timeout ); #ifdef __cplusplus diff --git a/qse/lib/cmn/Makefile.am b/qse/lib/cmn/Makefile.am index b0e8f565..426e46ae 100644 --- a/qse/lib/cmn/Makefile.am +++ b/qse/lib/cmn/Makefile.am @@ -48,6 +48,7 @@ libqsecmn_la_SOURCES = \ mbwc-str.c \ mem.c \ nwad.c \ + nwif.c \ nwio.c \ oht.c \ opt.c \ diff --git a/qse/lib/cmn/Makefile.in b/qse/lib/cmn/Makefile.in index 9e26e008..8dfda7bb 100644 --- a/qse/lib/cmn/Makefile.in +++ b/qse/lib/cmn/Makefile.in @@ -86,16 +86,17 @@ am_libqsecmn_la_OBJECTS = alg-rand.lo alg-search.lo alg-sort.lo \ assert.lo chr.lo cp949.lo cp950.lo dll.lo env.lo gdl.lo htb.lo \ fio.lo fma.lo fmt.lo fs.lo fs-err.lo fs-move.lo glob.lo \ hton.lo ipad.lo lda.lo main.lo mbwc.lo mbwc-str.lo mem.lo \ - nwad.lo nwio.lo oht.lo opt.lo path-basename.lo path-canon.lo \ - pio.lo pma.lo rbt.lo rex.lo sio.lo sll.lo slmb.lo stdio.lo \ - str-beg.lo str-cat.lo str-chr.lo str-cnv.lo str-cmp.lo \ - str-cpy.lo str-del.lo str-dup.lo str-dynm.lo str-dynw.lo \ - str-end.lo str-excl.lo str-fcpy.lo str-fnmat.lo str-incl.lo \ - str-len.lo str-pac.lo str-pbrk.lo str-put.lo str-rev.lo \ - str-rot.lo str-set.lo str-spl.lo str-spn.lo str-str.lo \ - str-subst.lo str-tok.lo str-trm.lo str-word.lo time.lo tio.lo \ - tre.lo tre-ast.lo tre-compile.lo tre-match-backtrack.lo \ - tre-match-parallel.lo tre-parse.lo tre-stack.lo utf8.lo xma.lo + nwad.lo nwif.lo nwio.lo oht.lo opt.lo path-basename.lo \ + path-canon.lo pio.lo pma.lo rbt.lo rex.lo sio.lo sll.lo \ + slmb.lo stdio.lo str-beg.lo str-cat.lo str-chr.lo str-cnv.lo \ + str-cmp.lo str-cpy.lo str-del.lo str-dup.lo str-dynm.lo \ + str-dynw.lo str-end.lo str-excl.lo str-fcpy.lo str-fnmat.lo \ + str-incl.lo str-len.lo str-pac.lo str-pbrk.lo str-put.lo \ + str-rev.lo str-rot.lo str-set.lo str-spl.lo str-spn.lo \ + str-str.lo str-subst.lo str-tok.lo str-trm.lo str-word.lo \ + time.lo tio.lo tre.lo tre-ast.lo tre-compile.lo \ + tre-match-backtrack.lo tre-match-parallel.lo tre-parse.lo \ + tre-stack.lo utf8.lo xma.lo libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS) libqsecmn_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ @@ -337,6 +338,7 @@ libqsecmn_la_SOURCES = \ mbwc-str.c \ mem.c \ nwad.c \ + nwif.c \ nwio.c \ oht.c \ opt.c \ @@ -502,6 +504,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mbwc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nwad.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nwif.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nwio.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oht.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opt.Plo@am__quote@ diff --git a/qse/lib/cmn/env.c b/qse/lib/cmn/env.c index 19b9ab1a..5f08faa5 100644 --- a/qse/lib/cmn/env.c +++ b/qse/lib/cmn/env.c @@ -160,13 +160,13 @@ static int expandstr (qse_env_t* env, qse_size_t inc) } #if defined(QSE_ENV_CHAR_IS_WCHAR) -static int insertw (qse_env_t* env, const qse_wchar_t* name, const qse_wchar_t* value) +static int insertw (qse_env_t* env, const qse_wchar_t* name, const qse_wchar_t* value[]) { - qse_size_t nl, vl, tl; + qse_size_t nl, vl, tl, i; nl = qse_wcslen (name); - vl = qse_wcslen (value); - + for (i = 0, vl = 0; value[i]; i++) vl += qse_wcslen(value[i]); + if (env->arr.len >= env->arr.capa && expandarr(env) <= -1) return -1; @@ -179,7 +179,8 @@ static int insertw (qse_env_t* env, const qse_wchar_t* name, const qse_wchar_t* env->str.len += qse_wcscpy (&env->str.ptr[env->str.len], name); env->str.ptr[env->str.len++] = QSE_WT('='); - env->str.len += qse_wcscpy (&env->str.ptr[env->str.len], value); + for (i = 0; value[i]; i++) + env->str.len += qse_wcscpy (&env->str.ptr[env->str.len], value[i]); env->str.ptr[++env->str.len] = QSE_WT('\0'); return 0; @@ -239,12 +240,12 @@ static int deletew (qse_env_t* env, const qse_wchar_t* name) } #else -static int insertm (qse_env_t* env, const qse_mchar_t* name, const qse_mchar_t* value) +static int insertm (qse_env_t* env, const qse_mchar_t* name, const qse_mchar_t* value[]) { - qse_size_t nl, vl, tl; + qse_size_t nl, vl, tl, i; nl = qse_mbslen (name); - vl = qse_mbslen (value); + for (i = 0, vl = 0; value[i]; i++) vl += qse_mbslen(value[i]); if (env->arr.len >= env->arr.capa && expandarr(env) <= -1) return -1; @@ -258,7 +259,8 @@ static int insertm (qse_env_t* env, const qse_mchar_t* name, const qse_mchar_t* env->str.len += qse_mbscpy (&env->str.ptr[env->str.len], name); env->str.ptr[env->str.len++] = QSE_MT('='); - env->str.len += qse_mbscpy (&env->str.ptr[env->str.len], value); + for (i = 0; value[i]; i++) + env->str.len += qse_mbscpy (&env->str.ptr[env->str.len], value[i]); env->str.ptr[++env->str.len] = QSE_MT('\0'); return 0; @@ -319,26 +321,27 @@ static int deletem (qse_env_t* env, const qse_mchar_t* name) #endif static QSE_INLINE int insert_wcs ( - qse_env_t* env, const qse_wchar_t* name, const qse_wchar_t* value) + qse_env_t* env, const qse_wchar_t* name, const qse_wchar_t* value[]) { #if defined(QSE_ENV_CHAR_IS_WCHAR) /* no conversion -> wchar */ return insertw (env, name, value); #else /* convert wchar to mchar */ - qse_mchar_t* namedup, * valuedup; + qse_mchar_t* namedup, * valuedup[2]; int n; namedup = qse_wcstombsdup (name, env->mmgr); /* TODO: ignore mbwcerr */ if (namedup == QSE_NULL) return -1; - valuedup = qse_wcstombsdup (value, env->mmgr); /* TODO: ignore mbwcerr */ + valuedup[0] = qse_wcsatombsdup (value, env->mmgr); /* TODO: ignore mbwcerr */ if (valuedup == QSE_NULL) { QSE_MMGR_FREE (env->mmgr, namedup); return -1; } + valuedup[1] = QSE_NULL; n = insertm (env, namedup, valuedup); - QSE_MMGR_FREE (env->mmgr, valuedup); + QSE_MMGR_FREE (env->mmgr, valuedup[0]); QSE_MMGR_FREE (env->mmgr, namedup); return n; @@ -346,23 +349,24 @@ static QSE_INLINE int insert_wcs ( } static QSE_INLINE int insert_mbs ( - qse_env_t* env, const qse_mchar_t* name, const qse_mchar_t* value) + qse_env_t* env, const qse_mchar_t* name, const qse_mchar_t* value[]) { #if defined(QSE_ENV_CHAR_IS_WCHAR) /* convert mchar to wchar */ - qse_wchar_t* namedup, * valuedup; + qse_wchar_t* namedup, * valuedup[2]; int n; namedup = qse_mbstowcsalldup (name, env->mmgr); if (namedup == QSE_NULL) return -1; - valuedup = qse_mbstowcsalldup (value, env->mmgr); - if (valuedup == QSE_NULL) + valuedup[0] = qse_mbsatowcsalldup (value, env->mmgr); + if (valuedup[0] == QSE_NULL) { QSE_MMGR_FREE (env->mmgr, namedup); return -1; } + valuedup[1] = QSE_NULL; n = insertw (env, namedup, valuedup); - QSE_MMGR_FREE (env->mmgr, valuedup); + QSE_MMGR_FREE (env->mmgr, valuedup[0]); QSE_MMGR_FREE (env->mmgr, namedup); return n; @@ -473,15 +477,16 @@ static qse_mchar_t* get_env (qse_env_t* env, const qse_mchar_t* name, int* free) static int insert_sys_wcs (qse_env_t* env, const qse_wchar_t* name) { #if defined(QSE_ENV_CHAR_IS_WCHAR) - qse_wchar_t* v; + qse_wchar_t* v[2]; int free; int ret = -1; - v = get_env (env, name, &free); - if (v) + v[0] = get_env (env, name, &free); + if (v[0]) { + v[1] = QSE_NULL; ret = insertw (env, name, v); - if (free) QSE_MMGR_FREE (env->mmgr, v); + if (free) QSE_MMGR_FREE (env->mmgr, v[0]); } return ret; #else @@ -516,15 +521,16 @@ static int insert_sys_mbs (qse_env_t* env, const qse_mchar_t* name) return ret; #else - qse_mchar_t* v; + qse_mchar_t* v[2]; int free; int ret = -1; - v = get_env (env, name, &free); - if (v) + v[0] = get_env (env, name, &free); + if (v[0]) { + v[1] = QSE_NULL; ret = insertm (env, name, v); - if (free) QSE_MMGR_FREE (env->mmgr, v); + if (free) QSE_MMGR_FREE (env->mmgr, v[0]); } return ret; #endif @@ -620,6 +626,19 @@ done: int qse_env_insertwcs ( qse_env_t* env, const qse_wchar_t* name, const qse_wchar_t* value) +{ + if (value) + { + const qse_wchar_t* va[2]; + va[0] = value; + va[1] = QSE_NULL; + return insert_wcs (env, name, va); + } + else return insert_sys_wcs (env, name); +} + +int qse_env_insertwcsa ( + qse_env_t* env, const qse_wchar_t* name, const qse_wchar_t* value[]) { return value? insert_wcs (env, name, value): insert_sys_wcs (env, name); } @@ -627,9 +646,21 @@ int qse_env_insertwcs ( int qse_env_insertmbs ( qse_env_t* env, const qse_mchar_t* name, const qse_mchar_t* value) { - return value? insert_mbs (env, name, value): insert_sys_mbs (env, name); + if (value) + { + const qse_mchar_t* va[2]; + va[0] = value; + va[1] = QSE_NULL; + return insert_mbs (env, name, va); + } + else return insert_sys_mbs (env, name); } +int qse_env_insertmbsa ( + qse_env_t* env, const qse_mchar_t* name, const qse_mchar_t* value[]) +{ + return value? insert_mbs (env, name, value): insert_sys_mbs (env, name); +} int qse_env_deletewcs (qse_env_t* env, const qse_wchar_t* name) { diff --git a/qse/lib/cmn/nwad.c b/qse/lib/cmn/nwad.c index 32997bcc..8c4b18ec 100644 --- a/qse/lib/cmn/nwad.c +++ b/qse/lib/cmn/nwad.c @@ -20,105 +20,11 @@ #include #include +#include #include #include #include "mem.h" -#if defined(HAVE_NET_IF_H) -#include -#include - -#if !defined(IF_NAMESIZE) -# define IF_NAMESIZE 63 -#endif - -#if defined(HAVE_IF_NAMETOINDEX) -static QSE_INLINE unsigned int mbsn_to_ifindex (const qse_mchar_t* ptr, qse_size_t len) -{ - qse_mchar_t tmp[IF_NAMESIZE + 1]; - if (qse_mbsxncpy (tmp, QSE_COUNTOF(tmp), ptr, len) < len) - { - /* name too long */ - return 0; - } - return if_nametoindex (tmp); -} - -static QSE_INLINE unsigned int wcsn_to_ifindex (const qse_wchar_t* ptr, qse_size_t len) -{ - qse_mchar_t tmp[IF_NAMESIZE + 1]; - qse_size_t wl, ml; - - wl = len; ml = QSE_COUNTOF(tmp) - 1; - if (qse_wcsntombsn (ptr, &wl, tmp, &ml) <= -1) return 0; - tmp[ml] = QSE_MT('\0'); - return if_nametoindex (tmp); -} -#else -static QSE_INLINE unsigned int mbsn_to_ifindex (const qse_mchar_t* ptr, qse_size_t len) -{ - return 0U; -} -static QSE_INLINE unsigned int wcsn_to_ifindex (const qse_wchar_t* ptr, qse_size_t len) -{ - return 0U; -} -#endif /* HAVE_IF_NAMETOINDEX */ - -#if defined(HAVE_IF_INDEXTONAME) -static QSE_INLINE int ifindex_to_mbsn (unsigned int index, qse_mchar_t* buf, qse_size_t len) -{ - qse_mchar_t tmp[IF_NAMESIZE + 1]; - if (if_indextoname (index, tmp) == QSE_NULL) return 0; - return qse_mbsxcpy (buf, len, tmp); -} - -static QSE_INLINE int ifindex_to_wcsn (unsigned int index, qse_wchar_t* buf, qse_size_t len) -{ - qse_mchar_t tmp[IF_NAMESIZE + 1]; - qse_size_t ml, wl; - int x; - - if (if_indextoname (index, tmp) == QSE_NULL) return 0; - wl = len; - x = qse_mbstowcs (tmp, &ml, buf, &wl); - if (x == -2 && wl > 1) buf[wl - 1] = QSE_WT('\0'); - else if (x != 0) return 0; - return wl; -} - -#else -static QSE_INLINE int ifindex_to_mbsn (unsigned int index, qse_mchar_t* buf, qse_size_t len) -{ - return 0; -} -static QSE_INLINE int ifindex_to_wcsn (unsigned int index, qse_wchar_t* buf, qse_size_t len) -{ - return 0; -} -#endif /* HAVE_IF_INDEXTONAME */ - -#else /* HAVE_NET_IF_H */ - -static QSE_INLINE unsigned int mbsn_to_ifindex (const qse_mchar_t* ptr, qse_size_t len) -{ - return 0U; -} -static QSE_INLINE unsigned int wcsn_to_ifindex (const qse_wchar_t* ptr, qse_size_t len) -{ - return 0U; -} - -static QSE_INLINE int ifindex_to_mbsn (unsigned int index, qse_mchar_t* buf, qse_size_t len) -{ - return 0; -} -static QSE_INLINE int ifindex_to_wcsn (unsigned int index, qse_wchar_t* buf, qse_size_t len) -{ - return 0; -} -#endif /* HAVE_NET_IF_H */ - int qse_mbstonwad (const qse_mchar_t* str, qse_nwad_t* nwad) { return qse_mbsntonwad (str, qse_mbslen(str), nwad); @@ -178,7 +84,7 @@ int qse_mbsntonwad (const qse_mchar_t* str, qse_size_t len, qse_nwad_t* nwad) /* interface name as a scope id? */ const qse_mchar_t* stmp = p; do p++; while (p < end && *p != QSE_MT(']')); - tmpad.u.in6.scope = mbsn_to_ifindex (stmp, p - stmp); + tmpad.u.in6.scope = qse_nwifmbsntoindex (stmp, p - stmp); if (tmpad.u.in6.scope <= 0) return -1; } @@ -240,7 +146,7 @@ int qse_mbsntonwad (const qse_mchar_t* str, qse_size_t len, qse_nwad_t* nwad) /* interface name as a scope id? */ const qse_mchar_t* stmp = p; do p++; while (p < end); - tmpad.u.in6.scope = mbsn_to_ifindex (stmp, p - stmp); + tmpad.u.in6.scope = qse_nwifmbsntoindex (stmp, p - stmp); if (tmpad.u.in6.scope <= 0) return -1; } } @@ -342,7 +248,7 @@ int qse_wcsntonwad (const qse_wchar_t* str, qse_size_t len, qse_nwad_t* nwad) /* interface name as a scope id? */ const qse_wchar_t* stmp = p; do p++; while (p < end && *p != QSE_WT(']')); - tmpad.u.in6.scope = wcsn_to_ifindex (stmp, p - stmp); + tmpad.u.in6.scope = qse_nwifwcsntoindex (stmp, p - stmp); if (tmpad.u.in6.scope <= 0) return -1; } @@ -404,7 +310,7 @@ int qse_wcsntonwad (const qse_wchar_t* str, qse_size_t len, qse_nwad_t* nwad) /* interface name as a scope id? */ const qse_wchar_t* stmp = p; do p++; while (p < end); - tmpad.u.in6.scope = wcsn_to_ifindex (stmp, p - stmp); + tmpad.u.in6.scope = qse_nwifwcsntoindex (stmp, p - stmp); if (tmpad.u.in6.scope <= 0) return -1; } } @@ -489,8 +395,11 @@ qse_size_t qse_nwadtombs ( if (!(flags & QSE_NWADTOMBS_ADDR) || nwad->u.in6.port != 0) { - if (xlen + 1 >= len) goto done; - buf[xlen++] = QSE_MT('['); + if (flags & QSE_NWADTOMBS_ADDR) + { + if (xlen + 1 >= len) goto done; + buf[xlen++] = QSE_MT('['); + } } } @@ -509,7 +418,7 @@ qse_size_t qse_nwadtombs ( if (xlen + 1 >= len) goto done; - tmp = ifindex_to_mbsn (nwad->u.in6.scope, &buf[xlen], len - xlen); + tmp = qse_nwifindextombs (nwad->u.in6.scope, &buf[xlen], len - xlen); if (tmp <= 0) { xlen += qse_fmtuintmaxtombs ( @@ -525,11 +434,11 @@ qse_size_t qse_nwadtombs ( if (!(flags & QSE_NWADTOMBS_ADDR) || nwad->u.in6.port != 0) { - if (xlen + 1 >= len) goto done; - buf[xlen++] = QSE_MT(']'); - if (flags & QSE_NWADTOMBS_ADDR) { + if (xlen + 1 >= len) goto done; + buf[xlen++] = QSE_MT(']'); + if (xlen + 1 >= len) goto done; buf[xlen++] = QSE_MT(':'); } @@ -594,8 +503,11 @@ qse_size_t qse_nwadtowcs ( if (!(flags & QSE_NWADTOMBS_ADDR) || nwad->u.in6.port != 0) { - if (xlen + 1 >= len) goto done; - buf[xlen++] = QSE_WT('['); + if (flags & QSE_NWADTOMBS_ADDR) + { + if (xlen + 1 >= len) goto done; + buf[xlen++] = QSE_WT('['); + } } } @@ -613,7 +525,7 @@ qse_size_t qse_nwadtowcs ( if (xlen + 1 >= len) goto done; - tmp = ifindex_to_wcsn (nwad->u.in6.scope, &buf[xlen], len - xlen); + tmp = qse_nwifindextowcs (nwad->u.in6.scope, &buf[xlen], len - xlen); if (tmp <= 0) { xlen += qse_fmtuintmaxtowcs ( @@ -629,11 +541,11 @@ qse_size_t qse_nwadtowcs ( if (!(flags & QSE_NWADTOMBS_ADDR) || nwad->u.in6.port != 0) { - if (xlen + 1 >= len) goto done; - buf[xlen++] = QSE_WT(']'); - if (flags & QSE_NWADTOMBS_ADDR) { + if (xlen + 1 >= len) goto done; + buf[xlen++] = QSE_WT(']'); + if (xlen + 1 >= len) goto done; buf[xlen++] = QSE_WT(':'); } diff --git a/qse/lib/cmn/nwif.c b/qse/lib/cmn/nwif.c new file mode 100644 index 00000000..c961fa06 --- /dev/null +++ b/qse/lib/cmn/nwif.c @@ -0,0 +1,296 @@ +/* + * $Id$ + * + Copyright 2006-2012 Chung, Hyung-Hwan. + This file is part of QSE. + + QSE is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + QSE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with QSE. If not, see . + */ + +#include +#include +#include +#include "mem.h" + +#if defined(_WIN32) + /* TODO: */ +#elif defined(__OS2__) + /* TODO: */ +#elif defined(__DOS__) + /* TODO: */ +#else +# include "syscall.h" +# include +# if defined(HAVE_SYS_IOCTL_H) +# include +# endif +# if defined(HAVE_NET_IF_H) +# include +# endif +# if !defined(IF_NAMESIZE) +# define IF_NAMESIZE 63 +# endif +#endif + +unsigned int qse_nwifmbstoindex (const qse_mchar_t* ptr) +{ +#if defined(_WIN32) + /* TODO: */ + return 0u; +#elif defined(__OS2__) + /* TODO: */ + return 0u; +#elif defined(__DOS__) + /* TODO: */ + return 0u; + +#elif defined(SIOCGIFINDEX) + int h, x; + qse_size_t len; + struct ifreq ifr; + + h = socket (AF_INET, SOCK_DGRAM, 0); + if (h <= -1) return 0u; + + QSE_MEMSET (&ifr, 0, QSE_SIZEOF(ifr)); + len = qse_mbsxcpy (ifr.ifr_name, QSE_COUNTOF(ifr.ifr_name), ptr); + if (ptr[len] != QSE_MT('\0')) return 0u; /* name too long */ + + x = ioctl (h, SIOCGIFINDEX, &ifr); + QSE_CLOSE (h); + + return (x <= -1)? 0u: ifr.ifr_ifindex; + +#elif defined(HAVE_IF_NAMETOINDEX) + qse_mchar_t tmp[IF_NAMESIZE + 1]; + qse_size_t len; + + len = qse_mbsxcpy (tmp, QSE_COUNTOF(tmp), ptr); + if (ptr[len] != QSE_MT('\0')) return 0u; /* name too long */ + return if_nametoindex (tmp); + +#else + return 0u; +#endif +} + +unsigned int qse_nwifmbsntoindex (const qse_mchar_t* ptr, qse_size_t len) +{ +#if defined(_WIN32) + /* TODO: */ + return 0u; +#elif defined(__OS2__) + /* TODO: */ + return 0u; +#elif defined(__DOS__) + /* TODO: */ + return 0u; + +#elif defined(SIOCGIFINDEX) + int h, x; + struct ifreq ifr; + + h = socket (AF_INET, SOCK_DGRAM, 0); + if (h <= -1) return 0u; + + QSE_MEMSET (&ifr, 0, QSE_SIZEOF(ifr)); + if (qse_mbsxncpy (ifr.ifr_name, QSE_COUNTOF(ifr.ifr_name), ptr, len) < len) return 0u; /* name too long */ + + x = ioctl (h, SIOCGIFINDEX, &ifr); + QSE_CLOSE (h); + + return (x <= -1)? 0u: ifr.ifr_ifindex; + +#elif defined(HAVE_IF_NAMETOINDEX) + qse_mchar_t tmp[IF_NAMESIZE + 1]; + if (qse_mbsxncpy (tmp, QSE_COUNTOF(tmp), ptr, len) < len) return 0u; /* name too long */ + return if_nametoindex (tmp); + +#else + return 0u; +#endif +} + +unsigned int qse_nwifwcstoindex (const qse_wchar_t* ptr) +{ +#if defined(_WIN32) + /* TODO: */ + return 0u; +#elif defined(__OS2__) + /* TODO: */ + return 0u; +#elif defined(__DOS__) + /* TODO: */ + return 0u; + +#elif defined(SIOCGIFINDEX) + int h, x; + struct ifreq ifr; + qse_size_t wl, ml; + + h = socket (AF_INET, SOCK_DGRAM, 0); + if (h <= -1) return 0u; + + ml = QSE_COUNTOF(ifr.ifr_name); + if (qse_wcstombs (ptr, &wl, ifr.ifr_name, &ml) <= -1) return 0; + + x = ioctl (h, SIOCGIFINDEX, &ifr); + QSE_CLOSE (h); + + return (x <= -1)? 0u: ifr.ifr_ifindex; + +#elif defined(HAVE_IF_NAMETOINDEX) + qse_mchar_t tmp[IF_NAMESIZE + 1]; + qse_size_t wl, ml; + + ml = QSE_COUNTOF(tmp); + if (qse_wcstombs (ptr, &wl, tmp, &ml) <= -1) return 0; + + return if_nametoindex (tmp); + +#else + return 0u; +#endif +} + +unsigned int qse_nwifwcsntoindex (const qse_wchar_t* ptr, qse_size_t len) +{ +#if defined(_WIN32) + /* TODO: */ + return 0u; +#elif defined(__OS2__) + /* TODO: */ + return 0u; +#elif defined(__DOS__) + /* TODO: */ + return 0u; + +#elif defined(SIOCGIFINDEX) + int h, x; + struct ifreq ifr; + qse_size_t wl, ml; + + h = socket (AF_INET, SOCK_DGRAM, 0); + if (h <= -1) return 0u; + + wl = len; ml = QSE_COUNTOF(ifr.ifr_name) - 1; + if (qse_wcsntombsn (ptr, &wl, ifr.ifr_name, &ml) <= -1) return 0; + ifr.ifr_name[ml] = QSE_MT('\0'); + + x = ioctl (h, SIOCGIFINDEX, &ifr); + QSE_CLOSE (h); + + return (x <= -1)? 0u: ifr.ifr_ifindex; + +#elif defined(HAVE_IF_NAMETOINDEX) + qse_mchar_t tmp[IF_NAMESIZE + 1]; + qse_size_t wl, ml; + + wl = len; ml = QSE_COUNTOF(tmp) - 1; + if (qse_wcsntombsn (ptr, &wl, tmp, &ml) <= -1) return 0; + tmp[ml] = QSE_MT('\0'); + return if_nametoindex (tmp); + +#else + return 0u; +#endif +} + +qse_size_t qse_nwifindextombs (unsigned int index, qse_mchar_t* buf, qse_size_t len) +{ +#if defined(_WIN32) + /* TODO: */ + return 0u; +#elif defined(__OS2__) + /* TODO: */ + return 0u; +#elif defined(__DOS__) + /* TODO: */ + return 0u; + +#elif defined(SIOCGIFNAME) + + int h, x; + struct ifreq ifr; + + h = socket (AF_INET, SOCK_DGRAM, 0); + if (h <= -1) return 0u; + + QSE_MEMSET (&ifr, 0, QSE_SIZEOF(ifr)); + ifr.ifr_ifindex = index; + + x = ioctl (h, SIOCGIFNAME, &ifr); + QSE_CLOSE (h); + + return (x <= -1)? 0: qse_mbsxcpy (buf, len, ifr.ifr_name); + +#elif defined(HAVE_IF_INDEXTONAME) + qse_mchar_t tmp[IF_NAMESIZE + 1]; + if (if_indextoname (index, tmp) == QSE_NULL) return 0; + return qse_mbsxcpy (buf, len, tmp); +#else + return 0; +#endif +} + +qse_size_t qse_nwifindextowcs (unsigned int index, qse_wchar_t* buf, qse_size_t len) +{ +#if defined(_WIN32) + /* TODO: */ + return 0u; +#elif defined(__OS2__) + /* TODO: */ + return 0u; +#elif defined(__DOS__) + /* TODO: */ + return 0u; + +#elif defined(SIOCGIFNAME) + + int h, x; + struct ifreq ifr; + qse_size_t wl, ml; + + h = socket (AF_INET, SOCK_DGRAM, 0); + if (h <= -1) return 0u; + + QSE_MEMSET (&ifr, 0, QSE_SIZEOF(ifr)); + ifr.ifr_ifindex = index; + + x = ioctl (h, SIOCGIFNAME, &ifr); + QSE_CLOSE (h); + + if (x <= -1) return 0; + + wl = len; + x = qse_mbstowcs (ifr.ifr_name, &ml, buf, &wl); + if (x == -2 && wl > 1) buf[wl - 1] = QSE_WT('\0'); + else if (x != 0) return 0; + return wl; + +#elif defined(HAVE_IF_INDEXTONAME) + qse_mchar_t tmp[IF_NAMESIZE + 1]; + qse_size_t ml, wl; + int x; + + if (if_indextoname (index, tmp) == QSE_NULL) return 0; + wl = len; + x = qse_mbstowcs (tmp, &ml, buf, &wl); + if (x == -2 && wl > 1) buf[wl - 1] = QSE_WT('\0'); + else if (x != 0) return 0; + return wl; +#else + return 0; +#endif +} diff --git a/qse/lib/net/Makefile.am b/qse/lib/net/Makefile.am index 2d738541..55471c83 100644 --- a/qse/lib/net/Makefile.am +++ b/qse/lib/net/Makefile.am @@ -20,6 +20,7 @@ libqsenet_la_SOURCES = \ httpd-resol.c \ httpd-std.c \ httpd-task.c \ + httpd-text.c \ upxd.c libqsenet_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir) diff --git a/qse/lib/net/Makefile.in b/qse/lib/net/Makefile.in index 91b1406e..5eb233bf 100644 --- a/qse/lib/net/Makefile.in +++ b/qse/lib/net/Makefile.in @@ -80,7 +80,8 @@ LTLIBRARIES = $(lib_LTLIBRARIES) libqsenet_la_DEPENDENCIES = am_libqsenet_la_OBJECTS = http.lo htre.lo htrd.lo httpd.lo \ httpd-cgi.lo httpd-dir.lo httpd-file.lo httpd-proxy.lo \ - httpd-resol.lo httpd-std.lo httpd-task.lo upxd.lo + httpd-resol.lo httpd-std.lo httpd-task.lo httpd-text.lo \ + upxd.lo libqsenet_la_OBJECTS = $(am_libqsenet_la_OBJECTS) libqsenet_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ @@ -277,6 +278,7 @@ libqsenet_la_SOURCES = \ httpd-resol.c \ httpd-std.c \ httpd-task.c \ + httpd-text.c \ upxd.c libqsenet_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir) @@ -365,6 +367,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd-resol.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd-std.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd-task.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd-text.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upxd.Plo@am__quote@ diff --git a/qse/lib/net/httpd-cgi.c b/qse/lib/net/httpd-cgi.c index 7bc975ba..6420447b 100644 --- a/qse/lib/net/httpd-cgi.c +++ b/qse/lib/net/httpd-cgi.c @@ -32,6 +32,7 @@ struct task_cgi_arg_t qse_mcstr_t path; qse_mcstr_t script; qse_mcstr_t suffix; + qse_mcstr_t docroot; int nph; qse_htre_t* req; }; @@ -45,6 +46,7 @@ struct task_cgi_t const qse_mchar_t* path; const qse_mchar_t* script; const qse_mchar_t* suffix; + const qse_mchar_t* docroot; qse_http_version_t version; int keepalive; /* taken from the request */ int nph; @@ -410,11 +412,13 @@ static int cgi_add_env ( const qse_mchar_t* path, const qse_mchar_t* script, const qse_mchar_t* suffix, + const qse_mchar_t* docroot, const qse_mchar_t* content_type, qse_size_t content_length, int chunked) { -/* TODO: error check */ +/* TODO: error check for various insert... */ + cgi_client_req_hdr_ctx_t ctx; qse_mchar_t buf[128]; const qse_http_version_t* v; @@ -436,11 +440,13 @@ static int cgi_add_env ( qse_env_insertmbs (env, QSE_MT("SCRIPT_FILENAME"), path); qse_env_insertmbs (env, QSE_MT("SCRIPT_NAME"), script); + qse_env_insertmbs (env, QSE_MT("DOCUMENT_ROOT"), docroot); if (suffix && suffix[0] != QSE_MT('\0')) + { + const qse_mchar_t* tmp[3] = { docroot, suffix, QSE_NULL}; qse_env_insertmbs (env, QSE_MT("PATH_INFO"), suffix); - -/* TODO: corrent all these name??? */ - //qse_env_insertmbs (env, QSE_MT("PATH_TRANSLATED"), qse_htre_getqpath(req)); + qse_env_insertmbsa (env, QSE_MT("PATH_TRANSLATED"), tmp); + } qse_env_insertmbs (env, QSE_MT("REQUEST_METHOD"), qse_htre_getqmethodname(req)); qse_env_insertmbs (env, QSE_MT("REQUEST_URI"), qse_htre_getqpath(req)); @@ -452,21 +458,19 @@ static int cgi_add_env ( if (chunked) qse_env_insertmbs (env, QSE_MT("TRANSFER_ENCODING"), QSE_MT("chunked")); + qse_env_insertmbs (env, "SERVER_SOFTWARE", qse_httpd_getname(httpd)); qse_nwadtombs (&client->local_addr, buf, QSE_COUNTOF(buf), QSE_NWADTOMBS_PORT); qse_env_insertmbs (env, QSE_MT("SERVER_PORT"), buf); qse_nwadtombs (&client->local_addr, buf, QSE_COUNTOF(buf), QSE_NWADTOMBS_ADDR); qse_env_insertmbs (env, QSE_MT("SERVER_ADDR"), buf); + qse_env_insertmbs (env, QSE_MT("SERVER_NAME"), buf); /* TODO: convert it to a host name */ + qse_nwadtombs (&client->remote_addr, buf, QSE_COUNTOF(buf), QSE_NWADTOMBS_PORT); qse_env_insertmbs (env, QSE_MT("REMOTE_PORT"), buf); qse_nwadtombs (&client->remote_addr, buf, QSE_COUNTOF(buf), QSE_NWADTOMBS_ADDR); qse_env_insertmbs (env, QSE_MT("REMOTE_ADDR"), buf); #if 0 - //qse_env_insertmbs (env, QSE_MT("DOCUMENT_ROOT"), QSE_MT("/")); - qse_env_insertmbs (env, "SERVER_NAME", - qse_env_insertmbs (env, "SERVER_ROOT", - qse_env_insertmbs (env, "DOCUMENT_ROOT", - qse_env_insertmbs (env, "REMOTE_PORT", qse_env_insertmbs (env, "REMOTE_USER", #endif @@ -700,9 +704,11 @@ static int task_init_cgi ( cgi->path = (qse_mchar_t*)(cgi + 1); cgi->script = cgi->path + arg->path.len + 1; cgi->suffix = cgi->script + arg->script.len + 1; + cgi->docroot = cgi->suffix + arg->suffix.len + 1; qse_mbscpy ((qse_mchar_t*)cgi->path, arg->path.ptr); qse_mbscpy ((qse_mchar_t*)cgi->script, arg->script.ptr); qse_mbscpy ((qse_mchar_t*)cgi->suffix, arg->suffix.ptr); + qse_mbscpy ((qse_mchar_t*)cgi->docroot, arg->docroot.ptr); cgi->version = *qse_htre_getversion(arg->req); cgi->keepalive = (arg->req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE); @@ -842,7 +848,7 @@ done: if (cgi_add_env ( httpd, client, cgi->env, arg->req, - cgi->path, cgi->script, cgi->suffix, + cgi->path, cgi->script, cgi->suffix, cgi->docroot, (tmp? tmp->ptr: QSE_NULL), content_length, (cgi->reqflags & CGI_REQ_FWDCHUNKED)) <= -1) { @@ -1457,6 +1463,7 @@ qse_httpd_task_t* qse_httpd_entaskcgi ( const qse_mchar_t* path, const qse_mchar_t* script, const qse_mchar_t* suffix, + const qse_mchar_t* docroot, int nph, qse_htre_t* req) { @@ -1465,6 +1472,7 @@ qse_httpd_task_t* qse_httpd_entaskcgi ( if (script == QSE_NULL) script = qse_htre_getqpath(req); if (suffix == QSE_NULL) suffix = QSE_MT(""); + if (docroot == QSE_NULL) docroot = QSE_MT(""); arg.path.ptr = path; arg.path.len = qse_mbslen(path); @@ -1472,6 +1480,8 @@ qse_httpd_task_t* qse_httpd_entaskcgi ( arg.script.len = qse_mbslen(script); arg.suffix.ptr = suffix; arg.suffix.len = qse_mbslen(suffix); + arg.docroot.ptr = docroot; + arg.docroot.len = qse_mbslen(docroot); arg.req = req; arg.nph = nph; @@ -1486,7 +1496,8 @@ qse_httpd_task_t* qse_httpd_entaskcgi ( QSE_SIZEOF(task_cgi_t) + ((arg.path.len + 1) * QSE_SIZEOF(*path)) + ((arg.script.len + 1) * QSE_SIZEOF(*script)) + - ((arg.suffix.len + 1) * QSE_SIZEOF(*suffix)) + ((arg.suffix.len + 1) * QSE_SIZEOF(*suffix)) + + ((arg.docroot.len + 1) * QSE_SIZEOF(*docroot)) ); } diff --git a/qse/lib/net/httpd-dir.c b/qse/lib/net/httpd-dir.c index 970fa8ff..71f0dcbf 100644 --- a/qse/lib/net/httpd-dir.c +++ b/qse/lib/net/httpd-dir.c @@ -28,7 +28,8 @@ typedef struct task_dir_t task_dir_t; struct task_dir_t { - const qse_mchar_t* path; + qse_mcstr_t path; + qse_mcstr_t qpath; qse_http_version_t version; int keepalive; }; @@ -39,8 +40,9 @@ struct task_dseg_t qse_http_version_t version; int keepalive; int chunked; - - const qse_mchar_t* path; + + qse_mcstr_t path; + qse_mcstr_t qpath; qse_dir_t* handle; qse_dirent_t* dent; @@ -64,10 +66,15 @@ static int task_init_dseg ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) { task_dseg_t* xtn = qse_httpd_gettaskxtn (httpd, task); + task_dseg_t* arg = (task_dseg_t*)task->ctx; + + QSE_MEMCPY (xtn, arg, QSE_SIZEOF(*xtn)); + + xtn->path.ptr = (qse_mchar_t*)(xtn + 1); + qse_mbscpy ((qse_mchar_t*)xtn->path.ptr, arg->path.ptr); + xtn->qpath.ptr = xtn->path.ptr + xtn->path.len + 1; + qse_mbscpy ((qse_mchar_t*)xtn->qpath.ptr, arg->qpath.ptr); - QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn)); - qse_mbscpy ((qse_mchar_t*)(xtn + 1), xtn->path); - xtn->path = (qse_mchar_t*)(xtn + 1); task->ctx = xtn; return 0; @@ -227,14 +234,15 @@ static int task_main_dseg ( { int is_root; - is_root = (qse_mbscmp (ctx->path, QSE_MT("/")) == 0); + 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"), - ctx->path, (is_root? QSE_MT(""): QSE_MT("
  • ..
  • ")) + ctx->qpath.ptr, (is_root? QSE_MT(""): QSE_MT("
  • ..
  • ")) ); if (x == -1 || x >= ctx->bufrem) { @@ -297,7 +305,7 @@ static int task_main_dseg ( QSE_MT("
  • %s%s
  • "), encname, (ctx->dent->d_type == DT_DIR? QSE_MT("/"): QSE_MT("")), - ctx->dent->d_name, + ctx->dent->d_name, /* TODO: html escaping */ (ctx->dent->d_type == DT_DIR? QSE_MT("/"): QSE_MT("")) ); @@ -364,6 +372,7 @@ static qse_httpd_task_t* entask_directory_segment ( data.keepalive = dir->keepalive; data.chunked = dir->keepalive; data.path = dir->path; + data.qpath = dir->qpath; QSE_MEMSET (&task, 0, QSE_SIZEOF(task)); task.init = task_init_dseg; @@ -372,7 +381,7 @@ static qse_httpd_task_t* entask_directory_segment ( task.ctx = &data; qse_printf (QSE_T("Debug: entasking directory segment (%d)\n"), client->handle.i); - return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data) + qse_mbslen(data.path) + 1); + return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data) + data.path.len + 1 + data.qpath.len + 1); } /*------------------------------------------------------------------------*/ @@ -381,12 +390,15 @@ static int task_init_dir ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) { task_dir_t* xtn = qse_httpd_gettaskxtn (httpd, task); + task_dir_t* arg = (task_dir_t*)task->ctx; /* deep-copy the context data to the extension area */ - QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn)); + QSE_MEMCPY (xtn, arg, QSE_SIZEOF(*xtn)); - qse_mbscpy ((qse_mchar_t*)(xtn + 1), xtn->path); - xtn->path = (qse_mchar_t*)(xtn + 1); + xtn->path.ptr = (qse_mchar_t*)(xtn + 1); + qse_mbscpy ((qse_mchar_t*)xtn->path.ptr, arg->path.ptr); + 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 */ task->ctx = xtn; @@ -404,9 +416,9 @@ static QSE_INLINE int task_main_dir ( dir = (task_dir_t*)task->ctx; x = task; - if (qse_mbsend (dir->path, QSE_MT("/"))) + if (qse_mbsend (dir->path.ptr, QSE_MT("/"))) { - handle = QSE_OPENDIR (dir->path); + handle = QSE_OPENDIR (dir->path.ptr); if (handle) { x = qse_httpd_entaskformat ( @@ -446,7 +458,7 @@ static QSE_INLINE int task_main_dir ( qse_httpd_getname (httpd), qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0), (dir->keepalive? QSE_MT("keep-alive"): QSE_MT("close")), - dir->path + dir->qpath.ptr ); return (x == QSE_NULL)? -1: 0; } @@ -463,7 +475,10 @@ qse_httpd_task_t* qse_httpd_entaskdir ( task_dir_t data; QSE_MEMSET (&data, 0, QSE_SIZEOF(data)); - data.path = path; + data.path.ptr = 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.version = *qse_htre_getversion(req); data.keepalive = (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE); @@ -473,6 +488,6 @@ qse_httpd_task_t* qse_httpd_entaskdir ( task.ctx = &data; return qse_httpd_entask (httpd, client, pred, &task, - QSE_SIZEOF(task_dir_t) + qse_mbslen(path) + 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 9490cd6f..77756abf 100644 --- a/qse/lib/net/httpd-file.c +++ b/qse/lib/net/httpd-file.c @@ -32,7 +32,9 @@ typedef struct task_file_t task_file_t; struct task_file_t { - const qse_mchar_t* path; + qse_mcstr_t path; + qse_mcstr_t mime; + qse_http_range_t range; qse_mchar_t if_none_match[ETAG_LEN_MAX + 1]; qse_ntime_t if_modified_since; @@ -128,11 +130,20 @@ qse_printf (QSE_T("Debug: entasking file segment (%d)\n"), client->handle.i); static int task_init_file ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) { - task_file_t* xtn = qse_httpd_gettaskxtn (httpd, task); - QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn)); - qse_mbscpy ((qse_mchar_t*)(xtn + 1), xtn->path); - xtn->path = (qse_mchar_t*)(xtn + 1); - task->ctx = xtn; + task_file_t* file = qse_httpd_gettaskxtn (httpd, task); + task_file_t* arg = (task_file_t*)task->ctx; + + QSE_MEMCPY (file, arg, QSE_SIZEOF(*file)); + + file->path.ptr = (qse_mchar_t*)(file + 1); + qse_mbscpy ((qse_mchar_t*)file->path.ptr, arg->path.ptr); + if (arg->mime.ptr) + { + file->mime.ptr = file->path.ptr + file->path.len + 1; + qse_mbscpy ((qse_mchar_t*)file->mime.ptr, arg->mime.ptr); + } + + task->ctx = file; return 0; } @@ -154,7 +165,7 @@ static QSE_INLINE int task_main_file ( qse_printf (QSE_T("opening file %hs\n"), file->path); httpd->errnum = QSE_HTTPD_ENOERR; - if (httpd->scb->file.stat (httpd, file->path, &st) <= -1) + if (httpd->scb->file.stat (httpd, file->path.ptr, &st) <= -1) { int http_errnum; http_errnum = (httpd->errnum == QSE_HTTPD_ENOENT)? 404: @@ -166,7 +177,7 @@ qse_printf (QSE_T("opening file %hs\n"), file->path); } httpd->errnum = QSE_HTTPD_ENOERR; - if (httpd->scb->file.ropen (httpd, file->path, &handle) <= -1) + if (httpd->scb->file.ropen (httpd, file->path.ptr, &handle) <= -1) { int http_errnum; http_errnum = (httpd->errnum == QSE_HTTPD_ENOENT)? 404: @@ -206,7 +217,7 @@ qse_printf (QSE_T("opening file %hs\n"), file->path); qse_fmtuintmaxtombs (tmp[2], QSE_COUNTOF(tmp[2]), file->range.to, 10, -1, QSE_MT('\0'), QSE_NULL); qse_fmtuintmaxtombs (tmp[3], QSE_COUNTOF(tmp[3]), st.size, 10, -1, QSE_MT('\0'), QSE_NULL); - etag_len = qse_fmtuintmaxtombs (&etag[0], QSE_COUNTOF(etag) - etag_len, st.mtime, 16, -1, QSE_MT('\0'), QSE_NULL); + etag_len = qse_fmtuintmaxtombs (&etag[0], QSE_COUNTOF(etag), st.mtime, 16, -1, QSE_MT('\0'), QSE_NULL); etag[etag_len++] = QSE_MT('-'); etag_len += qse_fmtuintmaxtombs (&etag[etag_len], QSE_COUNTOF(etag) - etag_len, st.size, 16, -1, QSE_MT('\0'), QSE_NULL); etag[etag_len++] = QSE_MT('-'); @@ -221,9 +232,9 @@ qse_printf (QSE_T("opening file %hs\n"), file->path); qse_httpd_getname (httpd), qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0), (file->keepalive? QSE_MT("keep-alive"): QSE_MT("close")), - (st.mime? QSE_MT("Content-Type: "): QSE_MT("")), - (st.mime? st.mime: QSE_MT("")), - (st.mime? QSE_MT("\r\n"): QSE_MT("")), + (file->mime.len > 0? QSE_MT("Content-Type: "): QSE_MT("")), + (file->mime.len > 0? file->mime.ptr: QSE_MT("")), + (file->mime.len > 0? QSE_MT("\r\n"): QSE_MT("")), tmp[0], tmp[1], tmp[2], tmp[3], etag ); if (x) @@ -242,7 +253,7 @@ qse_printf (QSE_T("opening file %hs\n"), file->path); qse_mchar_t etag[ETAG_LEN_MAX + 1]; qse_size_t etag_len; - etag_len = qse_fmtuintmaxtombs (&etag[0], QSE_COUNTOF(etag) - etag_len, st.mtime, 16, -1, QSE_MT('\0'), QSE_NULL); + etag_len = qse_fmtuintmaxtombs (&etag[0], QSE_COUNTOF(etag), st.mtime, 16, -1, QSE_MT('\0'), QSE_NULL); etag[etag_len++] = QSE_MT('-'); etag_len += qse_fmtuintmaxtombs (&etag[etag_len], QSE_COUNTOF(etag) - etag_len, st.size, 16, -1, QSE_MT('\0'), QSE_NULL); etag[etag_len++] = QSE_MT('-'); @@ -281,9 +292,9 @@ qse_printf (QSE_T("opening file %hs\n"), file->path); qse_httpd_getname (httpd), qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0), (file->keepalive? QSE_MT("keep-alive"): QSE_MT("close")), - (st.mime? QSE_MT("Content-Type: "): QSE_MT("")), - (st.mime? st.mime: QSE_MT("")), - (st.mime? QSE_MT("\r\n"): QSE_MT("")), + (file->mime.len > 0? QSE_MT("Content-Type: "): QSE_MT("")), + (file->mime.len > 0? file->mime.ptr: QSE_MT("")), + (file->mime.len > 0? QSE_MT("\r\n"): QSE_MT("")), b_fsize, qse_httpd_fmtgmtimetobb (httpd, &st.mtime, 1), etag @@ -305,6 +316,7 @@ qse_httpd_task_t* qse_httpd_entaskfile ( qse_httpd_client_t* client, qse_httpd_task_t* pred, const qse_mchar_t* path, + const qse_mchar_t* mime, qse_htre_t* req) { qse_httpd_task_t task; @@ -312,7 +324,13 @@ qse_httpd_task_t* qse_httpd_entaskfile ( const qse_htre_hdrval_t* tmp; QSE_MEMSET (&data, 0, QSE_SIZEOF(data)); - data.path = path; + data.path.ptr = path; + data.path.len = qse_mbslen(path); + if (mime) + { + data.mime.ptr = mime; + data.mime.len = qse_mbslen(mime); + } data.version = *qse_htre_getversion(req); data.keepalive = (req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE); @@ -363,6 +381,6 @@ qse_httpd_task_t* qse_httpd_entaskfile ( task.ctx = &data; return qse_httpd_entask (httpd, client, pred, &task, - QSE_SIZEOF(task_file_t) + qse_mbslen(path) + 1); + QSE_SIZEOF(task_file_t) + data.path.len + 1 + data.mime.len + 1); } diff --git a/qse/lib/net/httpd-proxy.c b/qse/lib/net/httpd-proxy.c index 5a4f3d4e..8cd9718b 100644 --- a/qse/lib/net/httpd-proxy.c +++ b/qse/lib/net/httpd-proxy.c @@ -33,9 +33,9 @@ typedef struct task_proxy_arg_t task_proxy_arg_t; struct task_proxy_arg_t { - qse_nwad_t peer_nwad; + qse_nwad_t* peer_nwad; + qse_nwad_t* peer_local; qse_htre_t* req; - int nph; }; typedef struct task_proxy_t task_proxy_t; @@ -684,7 +684,10 @@ static int task_init_proxy ( proxy->version = *qse_htre_getversion(arg->req); proxy->keepalive = (arg->req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE); - proxy->peer.nwad = arg->peer_nwad; + proxy->peer.nwad = *arg->peer_nwad; + if (arg->peer_local) proxy->peer.local = *arg->peer_local; + else proxy->peer.local.type = arg->peer_nwad->type; + proxy->req = QSE_NULL; /* -------------------------------------------------------------------- @@ -694,6 +697,7 @@ static int task_init_proxy ( /* TODO: DETERMINE THIS SIZE */ len = 1024; + proxy->reqfwdbuf = qse_mbs_open (httpd->mmgr, 0, (len < 512? 512: len)); if (proxy->reqfwdbuf == QSE_NULL) goto oops; @@ -1442,13 +1446,15 @@ qse_httpd_task_t* qse_httpd_entaskproxy ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* pred, - const qse_nwad_t* nwad, + const qse_nwad_t* dst, + const qse_nwad_t* src, qse_htre_t* req) { qse_httpd_task_t task; task_proxy_arg_t arg; - arg.peer_nwad = *nwad; + arg.peer_nwad = dst; + arg.peer_local = src; arg.req = req; QSE_MEMSET (&task, 0, QSE_SIZEOF(task)); diff --git a/qse/lib/net/httpd-std.c b/qse/lib/net/httpd-std.c index bf2ad22d..f04a93bc 100644 --- a/qse/lib/net/httpd-std.c +++ b/qse/lib/net/httpd-std.c @@ -20,6 +20,10 @@ #include "httpd.h" #include "../cmn/mem.h" +#include +#include +#include +#include #if defined(_WIN32) # include @@ -55,6 +59,16 @@ #include /* TODO: remove this */ +#define DEFAULT_PORT 80 +#define DEFAULT_SECURE_PORT 443 + +struct server_xtn_t +{ + qse_mxstr_t docroot; +}; + +typedef struct server_xtn_t server_xtn_t; + /* ------------------------------------------------------------------- */ #if defined(_WIN32) @@ -296,6 +310,7 @@ static qse_ssize_t xsendfile_ssl ( typedef struct httpd_xtn_t httpd_xtn_t; struct httpd_xtn_t { + qse_httpd_cbstd_t* cbstd; #if defined(HAVE_SSL) SSL_CTX* ssl_ctx; #endif @@ -387,7 +402,7 @@ qse_httpd_t* qse_httpd_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize) if (httpd == QSE_NULL) return QSE_NULL; xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); - QSE_MEMSET (xtn, 0, xtnsize); + QSE_MEMSET (xtn, 0, QSE_SIZEOF(httpd_xtn_t) + xtnsize); #if defined(HAVE_SSL) /*init_xtn_ssl (xtn, "http01.pem", "http01.key");*/ @@ -402,6 +417,132 @@ void* qse_httpd_getxtnstd (qse_httpd_t* httpd) return (void*)((httpd_xtn_t*)QSE_XTN(httpd) + 1); } +static int parse_server_uri ( + qse_httpd_t* httpd, const qse_char_t* uri, + qse_httpd_server_t* server, const qse_char_t** docroot) +{ + qse_uint16_t default_port; + qse_cstr_t tmp; + + server->flags = 0; + + /* check the protocol part */ + tmp.ptr = uri; + while (*uri != QSE_T(':')) + { + if (*uri == QSE_T('\0')) + { + httpd->errnum = QSE_HTTPD_EINVAL; + return -1; + } + uri++; + } + tmp.len = uri - tmp.ptr; + if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("http")) == 0) + { + default_port = DEFAULT_PORT; + } + else if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("https")) == 0) + { + server->flags |= QSE_HTTPD_SERVER_SECURE; + default_port = DEFAULT_SECURE_PORT; + } + else + { + httpd->errnum = QSE_HTTPD_EINVAL; + return -1; + } + + uri++; /* skip : */ + if (*uri != QSE_T('/')) + { + httpd->errnum = QSE_HTTPD_EINVAL; + return -1; + } + uri++; /* skip / */ + if (*uri != QSE_T('/')) + { + httpd->errnum = QSE_HTTPD_EINVAL; + return -1; + } + uri++; /* skip / */ + + + tmp.ptr = uri; + while (*uri != QSE_T('\0') && *uri != QSE_T('/')) uri++; + tmp.len = uri - tmp.ptr; + + if (qse_strntonwad (tmp.ptr, tmp.len, &server->nwad) <= -1) + { + httpd->errnum = QSE_HTTPD_EINVAL; + return -1; + } + + *docroot = uri; + + if (server->nwad.type == QSE_NWAD_IN4) + { + if (server->nwad.u.in4.port == 0) + server->nwad.u.in4.port = qse_hton16(default_port); + } + else if (server->nwad.type == QSE_NWAD_IN6) + { + if (server->nwad.u.in6.port == 0) + server->nwad.u.in6.port = qse_hton16(default_port); + } + + return 0; +} + +static void predetach_server (qse_httpd_t* httpd, qse_httpd_server_t* server) +{ + server_xtn_t* server_xtn; + + server_xtn = (server_xtn_t*) qse_httpd_getserverxtn (httpd, server); + if (server_xtn->docroot.ptr) + { + QSE_MMGR_FREE (httpd->mmgr, server_xtn->docroot.ptr); + server_xtn->docroot.ptr = QSE_NULL; + server_xtn->docroot.len = 0; + } +} + +qse_httpd_server_t* qse_httpd_attachserverstd ( + qse_httpd_t* httpd, const qse_char_t* uri, qse_size_t xtnsize) +{ + qse_httpd_server_t server, * xserver; + const qse_char_t* docroot; + server_xtn_t* server_xtn; + + if (parse_server_uri (httpd, uri, &server, &docroot) <= -1) return QSE_NULL; + server.predetach = predetach_server; + + xserver = qse_httpd_attachserver ( + httpd, &server, QSE_SIZEOF(*server_xtn) + xtnsize); + if (xserver == QSE_NULL) return QSE_NULL; + + if (docroot[0] == QSE_T('/') && docroot[1] != QSE_T('\0')) + { + server_xtn = qse_httpd_getserverxtn (httpd, xserver); + +#if defined(QSE_CHAR_IS_MCHAR) + server_xtn->docroot.ptr = qse_mbsdup (docroot, httpd->mmgr); +#else + server_xtn->docroot.ptr = qse_wcstombsdup (docroot, httpd->mmgr); +#endif + if (server_xtn->docroot.ptr == QSE_NULL) + { + qse_httpd_detachserver (httpd, xserver); + httpd->errnum = QSE_HTTPD_ENOMEM; + return QSE_NULL; + } + + server_xtn->docroot.len = qse_mbslen(server_xtn->docroot.ptr); + } + + return xserver; +} + /* ------------------------------------------------------------------- */ union sockaddr_t @@ -524,10 +665,48 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server) /* remove the ip routing restriction that a packet can only * be sent using a local ip address. this option is useful * if transparency is achieved with TPROXY */ + +/* +ip rule add fwmark 0x1/0x1 lookup 100 +ip route add local 0.0.0.0/0 dev lo table 100 + +iptables -t mangle -A PREROUTING -p tcp -m socket --transparent -j DIVERT +iptables -t mangle -A DIVERT -j MARK --set-mark 0x1/0x1 +iptables -t mangle -A DIVERT -j ACCEPT + +iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 8000 + +---------------------------------------------------------------------- + +if the socket is bound to 99.99.99.99:8000, you may do... +iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-ip 99.99.99.99 --on-port 8000 + +iptables -t mangle -A PREROUTING -p tcp ! -s 127.0.0.0/255.0.0.0 --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-ip 0.0.0.0 --on-port 8000 + +IP_TRANSPRENT is needed for: +- accepting TPROXYed connections +- binding to a non-local IP address (IP address the local system doesn't have) +- using a non-local IP address as a source +- + */ flag = 1; setsockopt (fd, SOL_IP, IP_TRANSPARENT, &flag, QSE_SIZEOF(flag)); #endif + if (server->flags & QSE_HTTPD_SERVER_BINDTONWIF) + { + qse_mchar_t tmp[64]; + qse_size_t len; + + len = qse_nwifindextombs (server->nwif, tmp, QSE_COUNTOF(tmp)); + + if (len <= 0 || setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, tmp, len) <= -1) + { + /* TODO: logging ... */ + goto oops; + } + } + /* Solaris 8 returns EINVAL if QSE_SIZEOF(addr) is passed in as the * address size for AF_INET. */ /*if (bind (s, (struct sockaddr*)&addr, QSE_SIZEOF(addr)) <= -1) goto oops_esocket;*/ @@ -545,6 +724,8 @@ static int server_open (qse_httpd_t* httpd, qse_httpd_server_t* server) goto oops; #endif } + + if (listen (fd, 10) <= -1) goto oops; flag = fcntl (fd, F_GETFL); @@ -565,8 +746,7 @@ static void server_close (qse_httpd_t* httpd, qse_httpd_server_t* server) } static int server_accept ( - qse_httpd_t* httpd, - qse_httpd_server_t* server, qse_httpd_client_t* client) + qse_httpd_t* httpd, qse_httpd_server_t* server, qse_httpd_client_t* client) { sockaddr_t addr; @@ -616,6 +796,10 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n")); } #if defined(SO_ORIGINAL_DST) + /* if REDIRECT is used, SO_ORIGINAL_DST returns the original + * destination. If TPROXY is used, getsockname() above returns + * the original address. */ + addrlen = QSE_SIZEOF(addr); if (getsockopt (fd, SOL_IP, SO_ORIGINAL_DST, (char*)&addr, &addrlen) <= -1 || sockaddr_to_nwad (&addr, &client->orgdst_addr) <= -1) @@ -626,6 +810,16 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n")); client->orgdst_addr = client->local_addr; #endif + +#if 0 + client->initial_ifindex = resolve_ifindex (fd, client->local_addr); + if (client->ifindex <= -1) + { + /* the local_address is not one of a local address. + * it's probably proxied. */ + } +#endif + client->handle.i = fd; return 0; } @@ -635,27 +829,38 @@ qse_fprintf (QSE_STDERR, QSE_T("Error: too many client?\n")); static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer) { int fd = -1, flag; - sockaddr_t addr; - int addrsize; + sockaddr_t connaddr, bindaddr; + int connaddrsize, bindaddrsize; int connected = 1; - addrsize = nwad_to_sockaddr (&peer->nwad, &addr); - if (addrsize <= -1) + connaddrsize = nwad_to_sockaddr (&peer->nwad, &connaddr); + bindaddrsize = nwad_to_sockaddr (&peer->local, &bindaddr); + if (connaddrsize <= -1 || bindaddrsize <= -1) { qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); return -1; } - fd = socket (SOCKADDR_FAMILY(&addr), SOCK_STREAM, IPPROTO_TCP); + fd = socket (SOCKADDR_FAMILY(&connaddr), SOCK_STREAM, IPPROTO_TCP); if (fd <= -1) goto oops; +#if defined(IP_TRANSPARENT) + flag = 1; + setsockopt (fd, SOL_IP, IP_TRANSPARENT, &flag, QSE_SIZEOF(flag)); +#endif + if (bind (fd, (struct sockaddr*)&bindaddr, bindaddrsize) <= -1) + { + /* i won't care about binding faiulre */ + /* TODO: some logging for this failure though */ + } + flag = fcntl (fd, F_GETFD); if (flag >= 0) fcntl (fd, F_SETFD, flag | FD_CLOEXEC); flag = fcntl (fd, F_GETFL); if (flag >= 0) fcntl (fd, F_SETFL, flag | O_NONBLOCK); - if (connect (fd, (struct sockaddr*)&addr, addrsize) <= -1) + if (connect (fd, (struct sockaddr*)&connaddr, connaddrsize) <= -1) { if (errno != EINPROGRESS) goto oops; connected = 0; @@ -1006,14 +1211,6 @@ static int file_stat ( hst->mtime = QSE_SEC_TO_MSEC(st.st_mtime); #endif - hst->mime = qse_mbsend (path, QSE_MT(".html"))? QSE_MT("text/html"): - qse_mbsend (path, QSE_MT(".txt"))? QSE_MT("text/plain"): - qse_mbsend (path, QSE_MT(".jpg"))? QSE_MT("image/jpeg"): - qse_mbsend (path, QSE_MT(".mp4"))? QSE_MT("video/mp4"): - qse_mbsend (path, QSE_MT(".mp3"))? QSE_MT("audio/mpeg"): - qse_mbsend (path, QSE_MT(".c"))? QSE_MT("text/plain"): - qse_mbsend (path, QSE_MT(".h"))? QSE_MT("text/plain"): - QSE_NULL; return 0; } @@ -1133,7 +1330,8 @@ static qse_ssize_t client_recv ( } else { - ssize_t ret = recv (client->handle.i, buf, bufsize, 0); + ssize_t ret; + ret = recv (client->handle.i, buf, bufsize, 0); if (ret <= -1) qse_httpd_seterrnum (httpd, syserr_to_errnum(errno)); return ret; } @@ -1281,185 +1479,15 @@ qse_printf (QSE_T("HEADER OK %d[%hs] %d[%hs]\n"), (int)QSE_HTB_KLEN(pair), QSE_ return QSE_HTB_WALK_FORWARD; } -typedef struct target_t target_t; -struct target_t -{ - enum - { - TARGET_DIR, - TARGET_FILE, - TARGET_CGI - } type; - union - { - const qse_mchar_t* dir; - const qse_mchar_t* file; - struct - { - qse_mchar_t* path; - qse_mchar_t* script; - qse_mchar_t* suffix; - int nph; - } cgi; - } u; -}; - -static void dispose_target (qse_httpd_t* httpd, target_t* target) -{ - if (target->type == TARGET_CGI) - { - if (target->u.cgi.suffix) QSE_MMGR_FREE (httpd->mmgr, target->u.cgi.suffix); - if (target->u.cgi.script) QSE_MMGR_FREE (httpd->mmgr, target->u.cgi.script); - if (target->u.cgi.path) QSE_MMGR_FREE (httpd->mmgr, target->u.cgi.path); - } -} - -static int resolve_target ( - qse_httpd_t* httpd, qse_htre_t* req, target_t* target) -{ - static struct extinfo_t - { - const qse_mchar_t* ptr; - qse_size_t len; - int nph; - } extinfo[] = - { - { QSE_MT(".cgi"), 4, 0 }, - { QSE_MT(".nph"), 4, 1 } - }; - - qse_size_t i; - const qse_mchar_t* qpath; - qse_stat_t st; - - qpath = qse_htre_getqpath(req); - - QSE_MEMSET (target, 0, QSE_SIZEOF(*target)); - - if (QSE_STAT (qpath, &st) == 0 && S_ISDIR(st.st_mode)) - { -/* TODO: attempt the index file like index.html, index.cgi, etc. */ - /* it is a directory */ - target->type = TARGET_DIR; - target->u.dir = qpath; - } - else - { -/* TODO: attempt other segments if qpath is like - * /abc/x.cgi/y.cgi/ttt. currently, it tries x.cgi only. - * x.cgi could be a directory name . - */ - for (i = 0; i < QSE_COUNTOF(extinfo); i++) - { - const qse_mchar_t* ext; - - ext = qse_mbsstr (qpath, extinfo[i].ptr); - if (ext && (ext[extinfo[i].len] == QSE_MT('/') || - ext[extinfo[i].len] == QSE_MT('\0'))) - { - target->type = TARGET_CGI; - target->u.cgi.nph = extinfo[i].nph; - - if (ext[extinfo[i].len] == QSE_MT('/')) - { - /* TODO: combine path with document root */ - target->u.cgi.path = qse_mbsxdup (qpath, ext - qpath + extinfo[i].len, httpd->mmgr); - - target->u.cgi.script = qse_mbsxdup (qpath, ext - qpath + extinfo[i].len, httpd->mmgr); - target->u.cgi.suffix = qse_mbsdup (&ext[extinfo[i].len], httpd->mmgr); - - if (target->u.cgi.path == QSE_NULL || - target->u.cgi.script == QSE_NULL || - target->u.cgi.suffix == QSE_NULL) - { - dispose_target (httpd, target); - return -1; - } - } - else - { - /* TODO: combine path with document root */ - target->u.cgi.path = qse_mbsdup (qpath, httpd->mmgr); - - target->u.cgi.script = qse_mbsdup (qpath, httpd->mmgr); - - if (target->u.cgi.path == QSE_NULL || - target->u.cgi.script == QSE_NULL) - { - dispose_target (httpd, target); - return -1; - } - } - - return 0; - } - } - - - target->type = TARGET_FILE; - target->u.file = qpath; - } - - return 0; -} - -static qse_httpd_task_t* entask_target ( - qse_httpd_t* httpd, qse_httpd_client_t* client, - qse_htre_t* req, target_t* target) -{ - qse_httpd_task_t* task; - - switch (target->type) - { - case TARGET_DIR: - qse_httpd_discardcontent (httpd, req); - task = qse_httpd_entaskdir (httpd, client, QSE_NULL, target->u.dir, req); - break; - - case TARGET_FILE: - qse_httpd_discardcontent (httpd, req); - task = qse_httpd_entaskfile (httpd, client, QSE_NULL, target->u.file, req); - break; - - case TARGET_CGI: - if (qse_htre_getqmethodtype(req) == QSE_HTTP_POST && - !(req->attr.flags & QSE_HTRE_ATTR_LENGTH) && - !(req->attr.flags & QSE_HTRE_ATTR_CHUNKED)) - { - req->attr.flags &= ~QSE_HTRE_ATTR_KEEPALIVE; - - qse_httpd_discardcontent (httpd, req); - task = qse_httpd_entaskerror (httpd, client, QSE_NULL, 411, req); - if (task) - { - /* 411 Length Required - can't keep alive */ - task = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL); - } - } - else - { - task = qse_httpd_entaskcgi ( - httpd, client, QSE_NULL, target->u.cgi.path, - target->u.cgi.script, target->u.cgi.suffix, - target->u.cgi.nph, req); - } - break; - - default: - task = QSE_NULL; - break; - } - - return task; -} - static int process_request ( - qse_httpd_t* httpd, qse_httpd_client_t* client, - qse_htre_t* req, int peek) + qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, int peek) { int method; qse_httpd_task_t* task; int content_received; + httpd_xtn_t* xtn; + + xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); method = qse_htre_getqmethodtype(req); content_received = (qse_htre_getcontentlen(req) > 0); @@ -1528,17 +1556,30 @@ if (qse_htre_getcontentlen(req) > 0) { if (peek) { - target_t target; + qse_httpd_rsrc_t rsrc; - if (resolve_target (httpd, req, &target) <= -1) + if (method == QSE_HTTP_POST && + !(req->attr.flags & QSE_HTRE_ATTR_LENGTH) && + !(req->attr.flags & QSE_HTRE_ATTR_CHUNKED)) + { + req->attr.flags &= ~QSE_HTRE_ATTR_KEEPALIVE; + qse_httpd_discardcontent (httpd, req); + task = qse_httpd_entaskerror (httpd, client, QSE_NULL, 411, req); + if (task) + { + /* 411 Length Required - can't keep alive. Force disconnect */ + task = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL); + } + } + else if (xtn->cbstd->makersrc (httpd, client, req, &rsrc) <= -1) { qse_httpd_discardcontent (httpd, req); task = qse_httpd_entaskerror (httpd, client, QSE_NULL, 500, req); } else { - task = entask_target (httpd, client, req, &target); - dispose_target (httpd, &target); + task = qse_httpd_entaskrsrc (httpd, client, QSE_NULL, &rsrc, req); + if (xtn->cbstd->freersrc) xtn->cbstd->freersrc (httpd, client, req, &rsrc); } if (task == QSE_NULL) goto oops; } @@ -1674,7 +1715,7 @@ qse_printf (QSE_T("Host not included....\n")); #if 0 } #endif - task = qse_httpd_entaskproxy (httpd, client, QSE_NULL, &nwad, req); + task = qse_httpd_entaskproxy (httpd, client, QSE_NULL, &nwad, QSE_NULL, req); if (task == QSE_NULL) goto oops; } @@ -1722,7 +1763,9 @@ static int handle_request ( static qse_httpd_scb_t httpd_system_callbacks = { /* server */ - { server_open, server_close, server_accept }, + { server_open, + server_close, + server_accept }, { peer_open, peer_close, @@ -1767,8 +1810,196 @@ static qse_httpd_rcb_t httpd_request_callbacks = handle_request }; -int qse_httpd_loopstd (qse_httpd_t* httpd, qse_httpd_rcb_t* rcb, qse_ntime_t timeout) + +static void free_resource ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + qse_htre_t* req, qse_httpd_rsrc_t* target) { - if (rcb == QSE_NULL) rcb = &httpd_request_callbacks; - return qse_httpd_loop (httpd, &httpd_system_callbacks, rcb, timeout); + const qse_mchar_t* qpath = qse_htre_getqpath(req); + + switch (target->type) + { + case QSE_HTTPD_RSRC_CGI: + if (target->u.cgi.suffix) + QSE_MMGR_FREE (httpd->mmgr, (qse_mchar_t*)target->u.cgi.suffix); + if (target->u.cgi.script != qpath) + QSE_MMGR_FREE (httpd->mmgr, (qse_mchar_t*)target->u.cgi.script); + if (target->u.cgi.path != qpath) + QSE_MMGR_FREE (httpd->mmgr, (qse_mchar_t*)target->u.cgi.path); + + break; + + case QSE_HTTPD_RSRC_DIR: + if (target->u.dir.path != qpath) + QSE_MMGR_FREE (httpd->mmgr, (qse_mchar_t*)target->u.dir.path); + break; + + case QSE_HTTPD_RSRC_FILE: + if (target->u.cgi.path != qpath) + QSE_MMGR_FREE (httpd->mmgr, (qse_mchar_t*)target->u.cgi.path); + break; + + default: + /* nothing to do */ + break; + } +} + +static int make_resource ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + qse_htre_t* req, qse_httpd_rsrc_t* target) +{ + static struct extinfo_t + { + const qse_mchar_t* ptr; + qse_size_t len; + int nph; + } extinfo[] = + { + { QSE_MT(".cgi"), 4, 0 }, + { QSE_MT(".nph"), 4, 1 } + }; + + qse_size_t i; + const qse_mchar_t* qpath; + qse_stat_t st; + server_xtn_t* server_xtn; + qse_mchar_t* xpath; + + qpath = qse_htre_getqpath(req); + + QSE_MEMSET (target, 0, QSE_SIZEOF(*target)); + + server_xtn = qse_httpd_getserverxtn (httpd, client->server); +#if 0 +target->type = QSE_HTTPD_RSRC_PROXY; +target->u.proxy.dst = client->orgdst_addr; +target->u.proxy.src = client->remote_addr; +target->u.proxy.src.u.in4.port = 0; +return 0; +#endif + + if (server_xtn->docroot.ptr) + { + const qse_mchar_t* ta[3]; + ta[0] = server_xtn->docroot.ptr; + ta[1] = qpath; + ta[2] = QSE_NULL; + xpath = qse_mbsadup (ta, httpd->mmgr); + if (xpath == QSE_NULL) + { + httpd->errnum = QSE_HTTPD_ENOMEM; + return -1; + } + } + else xpath = qpath; + + if (QSE_STAT (xpath, &st) == 0 && S_ISDIR(st.st_mode)) + { +/* TODO: attempt the index file like index.html, index.cgi, etc. */ + /* it is a directory */ + target->type = QSE_HTTPD_RSRC_DIR; + target->u.dir.path = xpath; + } + else + { +/* TODO: attempt other segments if qpath is like + * /abc/x.cgi/y.cgi/ttt. currently, it tries x.cgi only. + * x.cgi could be a directory name . + */ + for (i = 0; i < QSE_COUNTOF(extinfo); i++) + { + const qse_mchar_t* ext; + + ext = qse_mbsstr (qpath, extinfo[i].ptr); + if (ext && (ext[extinfo[i].len] == QSE_MT('/') || + ext[extinfo[i].len] == QSE_MT('\0'))) + { + qse_mchar_t* script, * suffix, * docroot; + + if (ext[extinfo[i].len] == QSE_MT('/')) + { + if (xpath != qpath) + QSE_MMGR_FREE (httpd->mmgr, xpath); + + if (server_xtn->docroot.ptr) + { + xpath = qse_mbsxdup2 ( + server_xtn->docroot.ptr, server_xtn->docroot.len, + qpath, ext - qpath + extinfo[i].len, httpd->mmgr); + } + else + { + xpath = qse_mbsxdup (qpath, ext - qpath + extinfo[i].len, httpd->mmgr); + } + + script = qse_mbsxdup (qpath, ext - qpath + extinfo[i].len, httpd->mmgr); + suffix = qse_mbsdup (&ext[extinfo[i].len], httpd->mmgr); + + if (xpath == QSE_NULL || script == QSE_NULL || suffix == QSE_NULL) + { + if (suffix) QSE_MMGR_FREE (httpd->mmgr, suffix); + if (script) QSE_MMGR_FREE (httpd->mmgr, script); + if (xpath) QSE_MMGR_FREE (httpd->mmgr, xpath); + httpd->errnum = QSE_HTTPD_ENOMEM; + return -1; + } + + docroot = server_xtn->docroot.ptr; + } + else + { + script = qpath; + suffix = QSE_NULL; + docroot = QSE_NULL; + } + + target->type = QSE_HTTPD_RSRC_CGI; + target->u.cgi.nph = extinfo[i].nph; + target->u.cgi.path = xpath; + target->u.cgi.script = script; + target->u.cgi.suffix = suffix; + target->u.cgi.docroot = docroot; + + return 0; + } + } + + + target->type = QSE_HTTPD_RSRC_FILE; + target->u.file.path = xpath; + target->u.file.mime = + qse_mbsend (qpath, QSE_MT(".html"))? QSE_MT("text/html"): + qse_mbsend (qpath, QSE_MT(".txt"))? QSE_MT("text/plain"): + qse_mbsend (qpath, QSE_MT(".css"))? QSE_MT("text/css"): + qse_mbsend (qpath, QSE_MT(".xml"))? QSE_MT("text/xml"): + qse_mbsend (qpath, QSE_MT(".js"))? QSE_MT("application/javascript"): + qse_mbsend (qpath, QSE_MT(".jpg"))? QSE_MT("image/jpeg"): + qse_mbsend (qpath, QSE_MT(".png"))? QSE_MT("image/png"): + qse_mbsend (qpath, QSE_MT(".mp4"))? QSE_MT("video/mp4"): + qse_mbsend (qpath, QSE_MT(".mp3"))? QSE_MT("audio/mpeg"): + qse_mbsend (qpath, QSE_MT(".c"))? QSE_MT("text/plain"): + qse_mbsend (qpath, QSE_MT(".h"))? QSE_MT("text/plain"): + QSE_NULL; + } + + return 0; +} + +static qse_httpd_cbstd_t httpd_cbstd = +{ + make_resource, + free_resource +}; + +int qse_httpd_loopstd (qse_httpd_t* httpd, qse_httpd_cbstd_t* cbstd, qse_ntime_t timeout) +{ + httpd_xtn_t* xtn; + + xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); + + if (cbstd) xtn->cbstd = cbstd; + else xtn->cbstd = &httpd_cbstd; + + return qse_httpd_loop (httpd, &httpd_system_callbacks, &httpd_request_callbacks, timeout); } diff --git a/qse/lib/net/httpd-task.c b/qse/lib/net/httpd-task.c index e684622a..8eeeed9f 100644 --- a/qse/lib/net/httpd-task.c +++ b/qse/lib/net/httpd-task.c @@ -66,111 +66,6 @@ qse_httpd_task_t* qse_httpd_entaskdisconnect ( /*------------------------------------------------------------------------*/ -static int task_main_statictext ( - qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) -{ - qse_ssize_t n; - qse_size_t count = 0; - const qse_mchar_t* ptr = (const qse_mchar_t*)task->ctx; - - while (*ptr != QSE_MT('\0') && count < MAX_SEND_SIZE) - { - ptr++; count++; - } - -/* TODO: do i need to add code to skip this send if count is 0? */ - n = httpd->scb->client.send (httpd, client, task->ctx, count); - if (n <= -1) return -1; - - ptr = (const qse_mchar_t*)task->ctx + n; - if (*ptr == QSE_MT('\0')) return 0; - - task->ctx = (void*)ptr; - return 1; /* more work to do */ -} - -qse_httpd_task_t* qse_httpd_entaskstatictext ( - qse_httpd_t* httpd, - qse_httpd_client_t* client, - qse_httpd_task_t* pred, - const qse_mchar_t* text) -{ - qse_httpd_task_t task; - - QSE_MEMSET (&task, 0, QSE_SIZEOF(task)); - task.main = task_main_statictext; - task.ctx = (void*)text; - - return qse_httpd_entask (httpd, client, pred, &task, 0); -} - -/*------------------------------------------------------------------------*/ - -typedef struct task_text_t task_text_t; -struct task_text_t -{ - const qse_mchar_t* ptr; - qse_size_t left; -}; - -static int task_init_text ( - qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) -{ - task_text_t* xtn = qse_httpd_gettaskxtn (httpd, task); - - QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn)); - QSE_MEMCPY (xtn + 1, xtn->ptr, xtn->left); - xtn->ptr = (qse_mchar_t*)(xtn + 1); - - task->ctx = xtn; - return 0; -} - -static int task_main_text ( - qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) -{ - qse_ssize_t n; - qse_size_t count; - task_text_t* ctx = (task_text_t*)task->ctx; - - count = MAX_SEND_SIZE; - if (count >= ctx->left) count = ctx->left; - -/* TODO: do i need to add code to skip this send if count is 0? */ - n = httpd->scb->client.send (httpd, client, ctx->ptr, count); - if (n <= -1) return -1; - - ctx->left -= n; - if (ctx->left <= 0) return 0; - - ctx->ptr += n; - return 1; /* more work to do */ -} - -qse_httpd_task_t* qse_httpd_entasktext ( - qse_httpd_t* httpd, - qse_httpd_client_t* client, - qse_httpd_task_t* pred, - const qse_mchar_t* text) -{ - qse_httpd_task_t task; - task_text_t data; - - QSE_MEMSET (&data, 0, QSE_SIZEOF(data)); - data.ptr = text; - data.left = qse_mbslen(text); - - QSE_MEMSET (&task, 0, QSE_SIZEOF(task)); - task.init = task_init_text; - task.main = task_main_text; - task.ctx = &data; - - return qse_httpd_entask ( - httpd, client, pred, &task, QSE_SIZEOF(data) + data.left); -} - -/*------------------------------------------------------------------------*/ - /* TODO: send wide character string when QSE_CHAR_IS_WCHAR */ /*------------------------------------------------------------------------*/ @@ -447,21 +342,22 @@ qse_httpd_task_t* qse_httpd_entaskauth ( /*------------------------------------------------------------------------*/ -qse_httpd_task_t* qse_httpd_entaskpath ( +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* name, qse_htre_t* req) + qse_httpd_task_t* pred, const qse_mchar_t* dst, qse_htre_t* req) { - qse_stat_t st; - qse_httpd_task_t* task; + const qse_http_version_t* version; -/* TODO: LSTAT or STAT? should i not follow the symbolic link? */ -/* if (QSE_LSTAT (name, &st) == 0 && S_ISDIR(st.st_mode))*/ - if (QSE_STAT (name, &st) == 0 && S_ISDIR(st.st_mode)) - task = qse_httpd_entaskdir (httpd, client, pred, name, req); - else - task = qse_httpd_entaskfile (httpd, client, pred, name, req); + version = qse_htre_getversion(req); - return task; + 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); } /*------------------------------------------------------------------------*/ @@ -478,3 +374,61 @@ qse_httpd_task_t* qse_httpd_entaskconnect ( } #endif + +qse_httpd_task_t* qse_httpd_entaskrsrc ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_httpd_task_t* pred, + qse_httpd_rsrc_t* rsrc, + qse_htre_t* req) +{ + qse_httpd_task_t* task; + + switch (rsrc->type) + { + case QSE_HTTPD_RSRC_AUTH: + task = qse_httpd_entaskauth (httpd, client, QSE_NULL, rsrc->u.auth.realm, req); + break; + + case QSE_HTTPD_RSRC_CGI: + task = qse_httpd_entaskcgi ( + httpd, client, QSE_NULL, rsrc->u.cgi.path, + rsrc->u.cgi.script, rsrc->u.cgi.suffix, + rsrc->u.cgi.docroot, rsrc->u.cgi.nph, req); + break; + + case QSE_HTTPD_RSRC_DIR: + qse_httpd_discardcontent (httpd, req); + task = qse_httpd_entaskdir (httpd, client, QSE_NULL, rsrc->u.dir.path, req); + break; + + case QSE_HTTPD_RSRC_ERROR: + qse_httpd_discardcontent (httpd, req); + task = qse_httpd_entaskerror (httpd, client, QSE_NULL, rsrc->u.error, req); + + case QSE_HTTPD_RSRC_FILE: + qse_httpd_discardcontent (httpd, req); + task = qse_httpd_entaskfile (httpd, client, QSE_NULL, rsrc->u.file.path, rsrc->u.file.mime, req); + break; + + case QSE_HTTPD_RSRC_PROXY: + task = qse_httpd_entaskproxy (httpd, client, QSE_NULL, &rsrc->u.proxy.dst, &rsrc->u.proxy.src, req); + break; + + case QSE_HTTPD_RSRC_RELOC: + task = qse_httpd_entaskreloc (httpd, client, QSE_NULL, rsrc->u.reloc.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; + + default: + qse_httpd_discardcontent (httpd, req); + task = QSE_NULL; + httpd->errnum = QSE_HTTPD_EINVAL; + break; + } + + return task; +} diff --git a/qse/lib/net/httpd-text.c b/qse/lib/net/httpd-text.c new file mode 100644 index 00000000..0e7cac5f --- /dev/null +++ b/qse/lib/net/httpd-text.c @@ -0,0 +1,120 @@ +/* + * $Id$ + * + Copyright 2006-2012 Chung, Hyung-Hwan. + This file is part of QSE. + + QSE is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + QSE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with QSE. If not, see . + */ + +#include "httpd.h" +#include "../cmn/mem.h" +#include + +typedef struct task_text_t task_text_t; +struct task_text_t +{ + const qse_mchar_t* ptr; + qse_size_t left; +}; + +static int task_init_text ( + qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) +{ + task_text_t* xtn = qse_httpd_gettaskxtn (httpd, task); + + QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn)); + QSE_MEMCPY (xtn + 1, xtn->ptr, xtn->left); + xtn->ptr = (qse_mchar_t*)(xtn + 1); + + task->ctx = xtn; + return 0; +} + +static int task_main_text ( + qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) +{ + qse_ssize_t n; + qse_size_t count; + task_text_t* ctx = (task_text_t*)task->ctx; + + count = MAX_SEND_SIZE; + if (count >= ctx->left) count = ctx->left; + +/* TODO: do i need to add code to skip this send if count is 0? */ + n = httpd->scb->client.send (httpd, client, ctx->ptr, count); + if (n <= -1) return -1; + + ctx->left -= n; + if (ctx->left <= 0) return 0; + + ctx->ptr += n; + return 1; /* more work to do */ +} + + +qse_httpd_task_t* qse_httpd_entask_text ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_httpd_task_t* pred, + const qse_mchar_t* ptr, + qse_size_t len) +{ + qse_httpd_task_t task; + task_text_t data; + + QSE_MEMSET (&data, 0, QSE_SIZEOF(data)); + data.ptr = ptr; + data.left = len; + + QSE_MEMSET (&task, 0, QSE_SIZEOF(task)); + task.init = task_init_text; + task.main = task_main_text; + task.ctx = &data; + + return qse_httpd_entask ( + httpd, client, pred, + &task, QSE_SIZEOF(data) + data.left); +} + +qse_httpd_task_t* qse_httpd_entasktext ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_httpd_task_t* pred, + const qse_mchar_t* text, + const qse_mchar_t* mime, + qse_htre_t* req) +{ + qse_size_t tlen; + qse_mchar_t b_tlen[64]; + qse_http_version_t* version; + + version = qse_htre_getversion (req); + + tlen = qse_mbslen(text); + qse_fmtuintmaxtombs (b_tlen, QSE_COUNTOF(b_tlen), tlen, 10, -1, QSE_MT('\0'), QSE_NULL); + + pred = qse_httpd_entaskformat ( + httpd, client, pred, + QSE_MT("HTTP/%d.%d 200 OK\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: %s\r\nContent-Length: %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")), + mime, b_tlen + ); + if (pred == QSE_NULL) return QSE_NULL; + + return qse_httpd_entask_text (httpd, client, pred, text, tlen); +} diff --git a/qse/lib/net/httpd.c b/qse/lib/net/httpd.c index b8c5ae35..42240cd2 100644 --- a/qse/lib/net/httpd.c +++ b/qse/lib/net/httpd.c @@ -25,7 +25,6 @@ #include #include #include -#include #include @@ -39,11 +38,7 @@ struct htrd_xtn_t QSE_IMPLEMENT_COMMON_FUNCTIONS (httpd) -#define DEFAULT_PORT 80 -#define DEFAULT_SECURE_PORT 443 - -static void free_server_list ( - qse_httpd_t* httpd, qse_httpd_server_t* server); +static void free_server_list (qse_httpd_t* httpd); static int perform_client_task ( qse_httpd_t* httpd, void* mux, qse_ubi_t handle, int mask, void* cbarg); @@ -83,15 +78,14 @@ int qse_httpd_init (qse_httpd_t* httpd, qse_mmgr_t* mmgr) QSE_MEMSET (httpd, 0, QSE_SIZEOF(*httpd)); httpd->mmgr = mmgr; qse_mbscpy (httpd->sname, QSE_MT("QSE-HTTPD " QSE_PACKAGE_VERSION)); + return 0; } void qse_httpd_fini (qse_httpd_t* httpd) { /* TODO */ - free_server_list (httpd, httpd->server.list); - QSE_ASSERT (httpd->server.navail == 0); - httpd->server.list = QSE_NULL; + free_server_list (httpd); } void qse_httpd_stop (qse_httpd_t* httpd) @@ -305,16 +299,18 @@ static qse_httpd_client_t* new_client ( qse_htrd_setoption (client->htrd, QSE_HTRD_REQUEST | QSE_HTRD_TRAILERS | QSE_HTRD_CANONQPATH); + /* copy the public fields, + * keep the private fields initialized at 0 */ client->status = tmpl->status; - if (httpd->scb->client.accepted == QSE_NULL) client->status |= CLIENT_READY; - client->handle = tmpl->handle; client->handle2 = tmpl->handle2; client->remote_addr = tmpl->remote_addr; client->local_addr = tmpl->local_addr; client->orgdst_addr = tmpl->orgdst_addr; + client->server = tmpl->server; + client->initial_ifindex = tmpl->initial_ifindex; xtn = (htrd_xtn_t*)qse_htrd_getxtn (client->htrd); xtn->httpd = httpd; @@ -433,7 +429,8 @@ qse_printf (QSE_T("failed to accept from server %s\n"), tmp); /* TODO: check maximum number of client. if exceed call client.close */ - if (server->secure) clibuf.status |= CLIENT_SECURE; + if (server->flags & QSE_HTTPD_SERVER_SECURE) clibuf.status |= CLIENT_SECURE; + clibuf.server = server; client = new_client (httpd, &clibuf); if (client == QSE_NULL) @@ -523,13 +520,13 @@ static void deactivate_servers (qse_httpd_t* httpd) { qse_httpd_server_t* server; - for (server = httpd->server.list; server; server = server->next) + for (server = httpd->server.list.head; server; server = server->next) { - if (server->active) + if (server->flags & QSE_HTTPD_SERVER_ACTIVE) { httpd->scb->mux.delhnd (httpd, httpd->mux, server->handle); httpd->scb->server.close (httpd, server); - server->active = 0; + server->flags &= ~QSE_HTTPD_SERVER_ACTIVE; httpd->server.nactive--; } } @@ -539,7 +536,7 @@ static int activate_servers (qse_httpd_t* httpd) { qse_httpd_server_t* server; - for (server = httpd->server.list; server; server = server->next) + for (server = httpd->server.list.head; server; server = server->next) { if (httpd->scb->server.open (httpd, server) <= -1) { @@ -559,113 +556,75 @@ qse_printf (QSE_T("FAILED TO ADD SERVER HANDLE TO MUX....\n")); continue; } - server->active = 1; + server->flags |= QSE_HTTPD_SERVER_ACTIVE; httpd->server.nactive++; } return 0; } -static void free_server_list (qse_httpd_t* httpd, qse_httpd_server_t* server) +static void free_server_list (qse_httpd_t* httpd) { + qse_httpd_server_t* server; + + server = httpd->server.list.head; + while (server) { qse_httpd_server_t* next = server->next; - - httpd->scb->server.close (httpd, server); - qse_httpd_freemem (httpd, server); - httpd->server.navail--; - + qse_httpd_detachserver (httpd, server); server = next; } + + QSE_ASSERT (httpd->server.navail == 0); + QSE_ASSERT (httpd->server.list.head == QSE_NULL); + QSE_ASSERT (httpd->server.list.tail == QSE_NULL); } -static qse_httpd_server_t* parse_server_uri (qse_httpd_t* httpd, const qse_char_t* uri) -{ - qse_httpd_server_t* server; - qse_uint16_t default_port; - qse_cstr_t tmp; - - server = qse_httpd_allocmem (httpd, QSE_SIZEOF(*server)); - if (server == QSE_NULL) goto oops; /* alloc set error number. */ - - QSE_MEMSET (server, 0, QSE_SIZEOF(*server)); - - /* check the protocol part */ - tmp.ptr = uri; - while (*uri != QSE_T(':')) - { - if (*uri == QSE_T('\0')) - { - httpd->errnum = QSE_HTTPD_EINVAL; - goto oops; - } - uri++; - } - tmp.len = uri - tmp.ptr; - if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("http")) == 0) - { - server->secure = 0; - default_port = DEFAULT_PORT; - } - else if (qse_strxcmp (tmp.ptr, tmp.len, QSE_T("https")) == 0) - { - server->secure = 1; - default_port = DEFAULT_SECURE_PORT; - } - else goto oops; - - uri++; /* skip : */ - if (*uri != QSE_T('/')) - { - httpd->errnum = QSE_HTTPD_EINVAL; - goto oops; - } - uri++; /* skip / */ - if (*uri != QSE_T('/')) - { - httpd->errnum = QSE_HTTPD_EINVAL; - goto oops; - } - uri++; /* skip / */ - - if (qse_strtonwad (uri, &server->nwad) <= -1) - { - httpd->errnum = QSE_HTTPD_EINVAL; - goto oops; - } - - if (server->nwad.type == QSE_NWAD_IN4) - { - if (server->nwad.u.in4.port == 0) - server->nwad.u.in4.port = qse_hton16(default_port); - } - else if (server->nwad.type == QSE_NWAD_IN6) - { - if (server->nwad.u.in6.port == 0) - server->nwad.u.in6.port = qse_hton16(default_port); - } - - return server; - -oops: - if (server) qse_httpd_freemem (httpd, server); - return QSE_NULL; -} - - -int qse_httpd_addserver (qse_httpd_t* httpd, const qse_char_t* uri) +qse_httpd_server_t* qse_httpd_attachserver ( + qse_httpd_t* httpd, const qse_httpd_server_t* tmpl, qse_size_t xtnsize) { qse_httpd_server_t* server; - server = parse_server_uri (httpd, uri); - if (server == QSE_NULL) return -1; + server = qse_httpd_allocmem (httpd, QSE_SIZEOF(*server) + xtnsize); + if (server == QSE_NULL) return QSE_NULL; - server->next = httpd->server.list; - httpd->server.list = server; + QSE_MEMCPY (server, tmpl, QSE_SIZEOF(*server)); + QSE_MEMSET (server + 1, 0, xtnsize); + + server->flags &= ~QSE_HTTPD_SERVER_ACTIVE; + + /* chain the server to the tail of the list */ + server->prev = httpd->server.list.tail; + server->next = QSE_NULL; + if (httpd->server.list.tail) + httpd->server.list.tail->next = server; + else + httpd->server.list.head = server; + httpd->server.list.tail = server; httpd->server.navail++; - return 0; + return server; +} + +void qse_httpd_detachserver (qse_httpd_t* httpd, qse_httpd_server_t* server) +{ + qse_httpd_server_t* prev, * next; + + prev = server->prev; + next = server->next; + + QSE_ASSERT (!(server->flags & QSE_HTTPD_SERVER_ACTIVE)); + + if (server->predetach) server->predetach (httpd, server); + + qse_httpd_freemem (httpd, server); + httpd->server.navail--; + + if (prev) prev->next = next; + else httpd->server.list.head = next; + if (next) next->prev = prev; + else httpd->server.list.tail = prev; } /* --------------------------------------------------- */ @@ -1166,14 +1125,14 @@ qse_printf (QSE_T("MUX ADDHND CLIENT RW(ENTASK) %d\n"), client->handle.i); int qse_httpd_loop (qse_httpd_t* httpd, qse_httpd_scb_t* scb, qse_httpd_rcb_t* rcb, qse_ntime_t timeout) { - QSE_ASSERTX (httpd->server.list != QSE_NULL, + QSE_ASSERTX (httpd->server.list.head != QSE_NULL, "Add listeners before calling qse_httpd_loop()"); QSE_ASSERTX (httpd->client.list.head == QSE_NULL, "No client should exist when this loop is started"); if (scb == QSE_NULL || rcb == QSE_NULL || - httpd->server.list == QSE_NULL) + httpd->server.list.head == QSE_NULL) { httpd->errnum = QSE_HTTPD_EINVAL; return -1; diff --git a/qse/lib/net/httpd.h b/qse/lib/net/httpd.h index 23f6f149..1a91b7ab 100644 --- a/qse/lib/net/httpd.h +++ b/qse/lib/net/httpd.h @@ -58,7 +58,11 @@ struct qse_httpd_t struct { - qse_httpd_server_t* list; + struct + { + qse_httpd_server_t* head; + qse_httpd_server_t* tail; + } list; qse_size_t navail; qse_size_t nactive; } server; @@ -106,6 +110,14 @@ qse_httpd_task_t* qse_httpd_entask_error ( int keepalive ); +qse_httpd_task_t* qse_httpd_entask_text ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_httpd_task_t* pred, + const qse_mchar_t* ptr, + qse_size_t len; +); + #ifdef __cplusplus } #endif diff --git a/qse/samples/cmn/nwad01.c b/qse/samples/cmn/nwad01.c index 4c0654bf..7a3d1503 100644 --- a/qse/samples/cmn/nwad01.c +++ b/qse/samples/cmn/nwad01.c @@ -103,7 +103,8 @@ static int test_main (int argc, qse_char_t* argv[], qse_char_t* envp[]) QSE_WT("[::ffff:0:0]:60"), QSE_WT("[::ffff:192.168.1.1]:70"), QSE_WT("[::ffff:192.168.1.1%999]:70"), - QSE_WT("[::ffff:192.168.1.1%eth0]:70") + QSE_WT("[::ffff:192.168.1.1%eth0]:70"), + QSE_WT("[::ffff:192.168.1.1%1]:70") }; for (i = 0; i < QSE_COUNTOF(ipstr); i++) diff --git a/qse/samples/net/httpd01.c b/qse/samples/net/httpd01.c index 0b54c513..fd1ca9fa 100644 --- a/qse/samples/net/httpd01.c +++ b/qse/samples/net/httpd01.c @@ -53,7 +53,7 @@ static int httpd_main (int argc, qse_char_t* argv[]) for (i = 1; i < argc; i++) { - if (qse_httpd_addserver (httpd, argv[i]) <= -1) + if (qse_httpd_attachserverstd (httpd, argv[i], 0) == QSE_NULL) { qse_fprintf (QSE_STDERR, QSE_T("Failed to add httpd listener - %s\n"), argv[i]); diff --git a/qse/samples/net/httpd02.c b/qse/samples/net/httpd02.c index 50184018..99585f28 100644 --- a/qse/samples/net/httpd02.c +++ b/qse/samples/net/httpd02.c @@ -35,135 +35,14 @@ struct xtn_t qse_mchar_t basedir[4096]; }; -static int process_request ( - qse_httpd_t* httpd, qse_httpd_client_t* client, - qse_htre_t* req, int peek) +static int makersrc ( + qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, qse_httpd_rsrc_t* rsrc) { - int method; - qse_httpd_task_t* task; - int content_received; - xtn_t* xtn; - - method = qse_htre_getqmethodtype(req); - content_received = (qse_htre_getcontentlen(req) > 0); - - xtn = (xtn_t*) qse_httpd_getxtn (httpd); - - if (peek) qse_perdechttpstr (qse_htre_getqpath(req), qse_htre_getqpath(req)); - -qse_printf (QSE_T("================================\n")); -qse_printf (QSE_T("[%lu] %hs REQUEST ==> [%hs] version[%d.%d %hs] method[%hs]\n"), - (unsigned long)time(NULL), - (peek? QSE_MT("PEEK"): QSE_MT("HANDLE")), - qse_htre_getqpath(req), - qse_htre_getmajorversion(req), - qse_htre_getminorversion(req), - qse_htre_getverstr(req), - qse_htre_getqmethodname(req) -); -if (qse_htre_getqparam(req)) - qse_printf (QSE_T("PARAMS ==> [%hs]\n"), qse_htre_getqparam(req)); - - if (peek) - { - if (method != QSE_HTTP_POST && method != QSE_HTTP_PUT) - { - /* i'll discard request contents if the method is none of - * post and put */ - qse_httpd_discardcontent (httpd, req); - } - - if ((req->attr.flags & QSE_HTRE_ATTR_EXPECT100) && - (req->version.major > 1 || - (req->version.major == 1 && req->version.minor >= 1)) && - !content_received) - { -/* TODO: check method.... */ - /* "expect" in the header, version 1.1 or higher, - * and no content received yet */ - - /* TODO: determine if to return 100-continue or other errors */ - if (qse_httpd_entaskcontinue ( - httpd, client, QSE_NULL, req) == QSE_NULL) return -1; - } - } - - if (method == QSE_HTTP_GET || method == QSE_HTTP_POST) - { - const qse_mchar_t* qpath = qse_htre_getqpath(req); - const qse_mchar_t* dot = qse_mbsrchr (qpath, QSE_MT('.')); - - if (dot && qse_mbscmp (dot, QSE_MT(".cgi")) == 0) - { - if (peek) - { - /* cgi */ - if (method == QSE_HTTP_POST && - !(req->attr.flags & QSE_HTRE_ATTR_LENGTH) && - !(req->attr.flags & QSE_HTRE_ATTR_CHUNKED)) - { - req->attr.flags &= ~QSE_HTRE_ATTR_KEEPALIVE; - task = qse_httpd_entaskerror ( - httpd, client, QSE_NULL, 411, req); - /* 411 can't keep alive */ - if (task) qse_httpd_entaskdisconnect (httpd, client, QSE_NULL); - } - else - { - task = qse_httpd_entaskcgi ( - httpd, client, QSE_NULL, qpath, QSE_NULL, QSE_NULL, 0, req); - if (task == QSE_NULL) goto oops; - } - } - - return 0; - } - else - { - if (peek) - { -/* TODO: combine qpath with xtn->basedir */ - qse_httpd_discardcontent (httpd, req); - task = qse_httpd_entaskpath (httpd, client, QSE_NULL, qpath, req); - if (task == QSE_NULL) goto oops; - } - } - } - else - { - if (!peek) - { - task = qse_httpd_entaskerror (httpd, client, QSE_NULL, 405, req); - if (task == QSE_NULL) goto oops; - } - } - - if (!(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)) - { - if (!peek) - { - task = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL); - if (task == QSE_NULL) goto oops; - } - } - - return 0; - -oops: - /*qse_httpd_markbadclient (httpd, client);*/ return -1; } -static int peek_request ( - qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req) +static void freersrc (qse_httpd_t* httpd, qse_httpd_rsrc_t* rsrc) { - return process_request (httpd, client, req, 1); -} - -static int handle_request ( - qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req) -{ - return process_request (httpd, client, req, 0); } /* --------------------------------------------------------------------- */ @@ -180,7 +59,7 @@ static int httpd_main (int argc, qse_char_t* argv[]) { qse_httpd_t* httpd = QSE_NULL; int ret = -1, i; - static qse_httpd_rcb_t rcb = { peek_request, handle_request }; + static qse_httpd_cbstd_t cbstd = { makersrc, freersrc }; if (argc <= 1) { @@ -197,7 +76,7 @@ static int httpd_main (int argc, qse_char_t* argv[]) for (i = 1; i < argc; i++) { - if (qse_httpd_addserver (httpd, argv[i]) <= -1) + if (qse_httpd_attachserverstd (httpd, argv[i], 0) == QSE_NULL) { qse_fprintf (QSE_STDERR, QSE_T("Failed to add httpd listener - %s\n"), argv[i]); @@ -212,7 +91,7 @@ static int httpd_main (int argc, qse_char_t* argv[]) qse_httpd_setname (httpd, QSE_MT("httpd02/qse 1.0")); qse_httpd_setoption (httpd, QSE_HTTPD_CGIERRTONUL); - ret = qse_httpd_loopstd (httpd, &rcb, 10000); + ret = qse_httpd_loopstd (httpd, &cbstd, 10000); signal (SIGINT, SIG_DFL); signal (SIGPIPE, SIG_DFL);