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
This commit is contained in:
hyung-hwan 2012-09-25 02:47:25 +00:00
parent fdba865863
commit cb34385ded
28 changed files with 1466 additions and 815 deletions

9
qse/configure vendored
View File

@ -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

View File

@ -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],

View File

@ -22,6 +22,7 @@ pkginclude_HEADERS = \
mbwc.h \
mem.h \
nwad.h \
nwif.h \
nwio.h \
oht.h \
opt.h \

View File

@ -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:

View File

@ -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

View File

@ -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" {

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef _QSE_CMN_NWIF_H_
#define _QSE_CMN_NWIF_H_
#include <qse/types.h>
#include <qse/macros.h>
#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

View File

@ -299,6 +299,9 @@
/* Define to 1 if you have the <sys/epoll.h> header file. */
#undef HAVE_SYS_EPOLL_H
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#undef HAVE_SYS_IOCTL_H
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
*/
#undef HAVE_SYS_NDIR_H

View File

@ -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

View File

@ -48,6 +48,7 @@ libqsecmn_la_SOURCES = \
mbwc-str.c \
mem.c \
nwad.c \
nwif.c \
nwio.c \
oht.c \
opt.c \

View File

@ -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@

View File

@ -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)
{

View File

@ -20,105 +20,11 @@
#include <qse/cmn/nwad.h>
#include <qse/cmn/hton.h>
#include <qse/cmn/nwif.h>
#include <qse/cmn/str.h>
#include <qse/cmn/fmt.h>
#include "mem.h"
#if defined(HAVE_NET_IF_H)
#include <net/if.h>
#include <qse/cmn/mbwc.h>
#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(':');
}

296
qse/lib/cmn/nwif.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <qse/cmn/nwif.h>
#include <qse/cmn/str.h>
#include <qse/cmn/mbwc.h>
#include "mem.h"
#if defined(_WIN32)
/* TODO: */
#elif defined(__OS2__)
/* TODO: */
#elif defined(__DOS__)
/* TODO: */
#else
# include "syscall.h"
# include <sys/socket.h>
# if defined(HAVE_SYS_IOCTL_H)
# include <sys/ioctl.h>
# endif
# if defined(HAVE_NET_IF_H)
# include <net/if.h>
# 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
}

View File

@ -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)

View File

@ -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@

View File

@ -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))
);
}

View File

@ -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("<html><head></head><body><b>%s</b><ul>%s"),
ctx->path, (is_root? QSE_MT(""): QSE_MT("<li><a href='../'>..</a></li>"))
ctx->qpath.ptr, (is_root? QSE_MT(""): QSE_MT("<li><a href='../'>..</a></li>"))
);
if (x == -1 || x >= ctx->bufrem)
{
@ -297,7 +305,7 @@ static int task_main_dseg (
QSE_MT("<li><a href='%s%s'>%s%s</a></li>"),
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);
}

View File

@ -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);
}

View File

@ -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));

View File

@ -20,6 +20,10 @@
#include "httpd.h"
#include "../cmn/mem.h"
#include <qse/cmn/hton.h>
#include <qse/cmn/nwif.h>
#include <qse/cmn/mbwc.h>
#include <qse/cmn/str.h>
#if defined(_WIN32)
# include <winsock2.h>
@ -55,6 +59,16 @@
#include <qse/cmn/stdio.h> /* 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);
}

View File

@ -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;
}

120
qse/lib/net/httpd-text.c Normal file
View File

@ -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 <htrd://www.gnu.org/licenses/>.
*/
#include "httpd.h"
#include "../cmn/mem.h"
#include <qse/cmn/fmt.h>
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);
}

View File

@ -25,7 +25,6 @@
#include <qse/cmn/chr.h>
#include <qse/cmn/str.h>
#include <qse/cmn/mbwc.h>
#include <qse/cmn/hton.h>
#include <qse/cmn/stdio.h>
@ -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;

View File

@ -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

View File

@ -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++)

View File

@ -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]);

View File

@ -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);