Reorganized the directory structure
This commit is contained in:
45
lib/http/Makefile.am
Normal file
45
lib/http/Makefile.am
Normal file
@ -0,0 +1,45 @@
|
||||
AUTOMAKE_OPTIONS = nostdinc
|
||||
|
||||
CPPFLAGS_ALL_COMMON = \
|
||||
-I$(top_builddir)/include \
|
||||
-I$(top_srcdir)/include
|
||||
|
||||
if WIN32
|
||||
# you must adjust the value of DEFAULT_MODPOSTFIX according
|
||||
# to the first number in -version-info below
|
||||
CPPFLAGS_HTTPD_MOD = -DQSE_HTTPD_DEFAULT_MODPREFIX=\"libqsehttpd-\" -DQSE_HTTPD_DEFAULT_MODPOSTFIX=\"-1\"
|
||||
else
|
||||
CPPFLAGS_HTTPD_MOD = -DQSE_HTTPD_DEFAULT_MODPREFIX=\"$(libdir)/libqsehttpd-\" -DQSE_HTTPD_DEFAULT_MODPOSTFIX=\"\"
|
||||
endif
|
||||
|
||||
lib_LTLIBRARIES = libqsehttp.la
|
||||
libqsehttp_la_SOURCES = \
|
||||
httpd.h \
|
||||
upxd.h \
|
||||
http.c \
|
||||
htre.c \
|
||||
htrd.c \
|
||||
httpd.c \
|
||||
httpd-cgi.c \
|
||||
httpd-dir.c \
|
||||
httpd-file.c \
|
||||
httpd-proxy.c \
|
||||
httpd-std.c \
|
||||
httpd-std-dns.h \
|
||||
httpd-std-mod.h \
|
||||
httpd-std-urs.h \
|
||||
httpd-task.c \
|
||||
httpd-text.c \
|
||||
upxd.c
|
||||
|
||||
libqsehttp_la_CPPFLAGS = $(CPPFLAGS_ALL_COMMON) $(CPPFLAGS_HTTPD_MOD) $(LTDLINCL)
|
||||
libqsehttp_la_LDFLAGS = -L../si -L../cmn -version-info 1:0:0 -no-undefined
|
||||
libqsehttp_la_LIBADD = -lqsesi -lqsecmn $(SOCKET_LIBS) $(SENDFILE_LIBS) $(SSL_LIBS)
|
||||
|
||||
if ENABLE_LIBLTDL
|
||||
libqsehttp_la_LIBADD += $(LTDL_LIBS)
|
||||
else
|
||||
libqsehttp_la_LIBADD += $(DL_LIBS)
|
||||
endif
|
||||
|
||||
|
867
lib/http/Makefile.in
Normal file
867
lib/http/Makefile.in
Normal file
@ -0,0 +1,867 @@
|
||||
# Makefile.in generated by automake 1.16.2 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
@ENABLE_LIBLTDL_TRUE@am__append_1 = $(LTDL_LIBS)
|
||||
@ENABLE_LIBLTDL_FALSE@am__append_2 = $(DL_LIBS)
|
||||
subdir = lib/http
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_sign.m4 \
|
||||
$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
|
||||
$(top_srcdir)/m4/ax_cxx_namespace.m4 \
|
||||
$(top_srcdir)/m4/ax_lib_mysql.m4 $(top_srcdir)/m4/ax_numval.m4 \
|
||||
$(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
|
||||
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
|
||||
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/m4/lx_find_mpi.m4 \
|
||||
$(top_srcdir)/m4/qse_try_cflags.m4 $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/include/qse/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
am__installdirs = "$(DESTDIR)$(libdir)"
|
||||
LTLIBRARIES = $(lib_LTLIBRARIES)
|
||||
am__DEPENDENCIES_1 =
|
||||
@ENABLE_LIBLTDL_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
|
||||
@ENABLE_LIBLTDL_FALSE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
|
||||
libqsehttp_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
|
||||
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
|
||||
$(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3)
|
||||
am_libqsehttp_la_OBJECTS = libqsehttp_la-http.lo libqsehttp_la-htre.lo \
|
||||
libqsehttp_la-htrd.lo libqsehttp_la-httpd.lo \
|
||||
libqsehttp_la-httpd-cgi.lo libqsehttp_la-httpd-dir.lo \
|
||||
libqsehttp_la-httpd-file.lo libqsehttp_la-httpd-proxy.lo \
|
||||
libqsehttp_la-httpd-std.lo libqsehttp_la-httpd-task.lo \
|
||||
libqsehttp_la-httpd-text.lo libqsehttp_la-upxd.lo
|
||||
libqsehttp_la_OBJECTS = $(am_libqsehttp_la_OBJECTS)
|
||||
AM_V_lt = $(am__v_lt_@AM_V@)
|
||||
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
|
||||
am__v_lt_0 = --silent
|
||||
am__v_lt_1 =
|
||||
libqsehttp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(libqsehttp_la_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
DEFAULT_INCLUDES =
|
||||
depcomp = $(SHELL) $(top_srcdir)/ac/depcomp
|
||||
am__maybe_remake_depfiles = depfiles
|
||||
am__depfiles_remade = ./$(DEPDIR)/libqsehttp_la-htrd.Plo \
|
||||
./$(DEPDIR)/libqsehttp_la-htre.Plo \
|
||||
./$(DEPDIR)/libqsehttp_la-http.Plo \
|
||||
./$(DEPDIR)/libqsehttp_la-httpd-cgi.Plo \
|
||||
./$(DEPDIR)/libqsehttp_la-httpd-dir.Plo \
|
||||
./$(DEPDIR)/libqsehttp_la-httpd-file.Plo \
|
||||
./$(DEPDIR)/libqsehttp_la-httpd-proxy.Plo \
|
||||
./$(DEPDIR)/libqsehttp_la-httpd-std.Plo \
|
||||
./$(DEPDIR)/libqsehttp_la-httpd-task.Plo \
|
||||
./$(DEPDIR)/libqsehttp_la-httpd-text.Plo \
|
||||
./$(DEPDIR)/libqsehttp_la-httpd.Plo \
|
||||
./$(DEPDIR)/libqsehttp_la-upxd.Plo
|
||||
am__mv = mv -f
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
|
||||
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
|
||||
$(AM_CFLAGS) $(CFLAGS)
|
||||
AM_V_CC = $(am__v_CC_@AM_V@)
|
||||
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
|
||||
am__v_CC_0 = @echo " CC " $@;
|
||||
am__v_CC_1 =
|
||||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
|
||||
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
|
||||
am__v_CCLD_0 = @echo " CCLD " $@;
|
||||
am__v_CCLD_1 =
|
||||
SOURCES = $(libqsehttp_la_SOURCES)
|
||||
DIST_SOURCES = $(libqsehttp_la_SOURCES)
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
||||
# Read a list of newline-separated strings from the standard input,
|
||||
# and print each of them once, without duplicates. Input order is
|
||||
# *not* preserved.
|
||||
am__uniquify_input = $(AWK) '\
|
||||
BEGIN { nonempty = 0; } \
|
||||
{ items[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in items) print i; }; } \
|
||||
'
|
||||
# Make sure the list of sources is unique. This is necessary because,
|
||||
# e.g., the same source file might be shared among _SOURCES variables
|
||||
# for different programs/libraries.
|
||||
am__define_uniq_tagged_files = \
|
||||
list='$(am__tagged_files)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | $(am__uniquify_input)`
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/ac/depcomp
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
BUILD_MODE = @BUILD_MODE@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DL_LIBS = @DL_LIBS@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO = @ECHO@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GREP = @GREP@
|
||||
HAVE_CXX = @HAVE_CXX@
|
||||
HAVE_CXX11 = @HAVE_CXX11@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBM = @LIBM@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIBTOOL_DEPS = @LIBTOOL_DEPS@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTDL_LIBS = @LTDL_LIBS@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
MPICC = @MPICC@
|
||||
MPI_CFLAGS = @MPI_CFLAGS@
|
||||
MPI_CLDFLAGS = @MPI_CLDFLAGS@
|
||||
MYSQL_CFLAGS = @MYSQL_CFLAGS@
|
||||
MYSQL_CONFIG = @MYSQL_CONFIG@
|
||||
MYSQL_LDFLAGS = @MYSQL_LDFLAGS@
|
||||
MYSQL_LIBS = @MYSQL_LIBS@
|
||||
MYSQL_VERSION = @MYSQL_VERSION@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
|
||||
PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
|
||||
PACKAGE_VERSION_PATCH = @PACKAGE_VERSION_PATCH@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PTHREAD_CC = @PTHREAD_CC@
|
||||
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
|
||||
PTHREAD_LIBS = @PTHREAD_LIBS@
|
||||
QSE_PROJECT_AUTHOR = @QSE_PROJECT_AUTHOR@
|
||||
QSE_PROJECT_URL = @QSE_PROJECT_URL@
|
||||
QUADMATH_LIBS = @QUADMATH_LIBS@
|
||||
RANLIB = @RANLIB@
|
||||
RM = @RM@
|
||||
RMDIR = @RMDIR@
|
||||
SED = @SED@
|
||||
SENDFILE_LIBS = @SENDFILE_LIBS@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
SOCKET_LIBS = @SOCKET_LIBS@
|
||||
SSL_LIBS = @SSL_LIBS@
|
||||
STRIP = @STRIP@
|
||||
TRUE = @TRUE@
|
||||
UCI_LIBS = @UCI_LIBS@
|
||||
UNICOWS_LIBS = @UNICOWS_LIBS@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
ax_pthread_config = @ax_pthread_config@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
AUTOMAKE_OPTIONS = nostdinc
|
||||
CPPFLAGS_ALL_COMMON = \
|
||||
-I$(top_builddir)/include \
|
||||
-I$(top_srcdir)/include
|
||||
|
||||
@WIN32_FALSE@CPPFLAGS_HTTPD_MOD = -DQSE_HTTPD_DEFAULT_MODPREFIX=\"$(libdir)/libqsehttpd-\" -DQSE_HTTPD_DEFAULT_MODPOSTFIX=\"\"
|
||||
|
||||
# you must adjust the value of DEFAULT_MODPOSTFIX according
|
||||
# to the first number in -version-info below
|
||||
@WIN32_TRUE@CPPFLAGS_HTTPD_MOD = -DQSE_HTTPD_DEFAULT_MODPREFIX=\"libqsehttpd-\" -DQSE_HTTPD_DEFAULT_MODPOSTFIX=\"-1\"
|
||||
lib_LTLIBRARIES = libqsehttp.la
|
||||
libqsehttp_la_SOURCES = \
|
||||
httpd.h \
|
||||
upxd.h \
|
||||
http.c \
|
||||
htre.c \
|
||||
htrd.c \
|
||||
httpd.c \
|
||||
httpd-cgi.c \
|
||||
httpd-dir.c \
|
||||
httpd-file.c \
|
||||
httpd-proxy.c \
|
||||
httpd-std.c \
|
||||
httpd-std-dns.h \
|
||||
httpd-std-mod.h \
|
||||
httpd-std-urs.h \
|
||||
httpd-task.c \
|
||||
httpd-text.c \
|
||||
upxd.c
|
||||
|
||||
libqsehttp_la_CPPFLAGS = $(CPPFLAGS_ALL_COMMON) $(CPPFLAGS_HTTPD_MOD) $(LTDLINCL)
|
||||
libqsehttp_la_LDFLAGS = -L../si -L../cmn -version-info 1:0:0 -no-undefined
|
||||
libqsehttp_la_LIBADD = -lqsesi -lqsecmn $(SOCKET_LIBS) \
|
||||
$(SENDFILE_LIBS) $(SSL_LIBS) $(am__append_1) $(am__append_2)
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .lo .o .obj
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/http/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign lib/http/Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
|
||||
list2=; for p in $$list; do \
|
||||
if test -f $$p; then \
|
||||
list2="$$list2 $$p"; \
|
||||
else :; fi; \
|
||||
done; \
|
||||
test -z "$$list2" || { \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
|
||||
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
|
||||
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
|
||||
}
|
||||
|
||||
uninstall-libLTLIBRARIES:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
|
||||
for p in $$list; do \
|
||||
$(am__strip_dir) \
|
||||
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
|
||||
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
|
||||
done
|
||||
|
||||
clean-libLTLIBRARIES:
|
||||
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
|
||||
@list='$(lib_LTLIBRARIES)'; \
|
||||
locs=`for p in $$list; do echo $$p; done | \
|
||||
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
|
||||
sort -u`; \
|
||||
test -z "$$locs" || { \
|
||||
echo rm -f $${locs}; \
|
||||
rm -f $${locs}; \
|
||||
}
|
||||
|
||||
libqsehttp.la: $(libqsehttp_la_OBJECTS) $(libqsehttp_la_DEPENDENCIES) $(EXTRA_libqsehttp_la_DEPENDENCIES)
|
||||
$(AM_V_CCLD)$(libqsehttp_la_LINK) -rpath $(libdir) $(libqsehttp_la_OBJECTS) $(libqsehttp_la_LIBADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsehttp_la-htrd.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsehttp_la-htre.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsehttp_la-http.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsehttp_la-httpd-cgi.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsehttp_la-httpd-dir.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsehttp_la-httpd-file.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsehttp_la-httpd-proxy.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsehttp_la-httpd-std.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsehttp_la-httpd-task.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsehttp_la-httpd-text.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsehttp_la-httpd.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsehttp_la-upxd.Plo@am__quote@ # am--include-marker
|
||||
|
||||
$(am__depfiles_remade):
|
||||
@$(MKDIR_P) $(@D)
|
||||
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
|
||||
|
||||
am--depfiles: $(am__depfiles_remade)
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
|
||||
|
||||
.c.obj:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
|
||||
.c.lo:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
libqsehttp_la-http.lo: http.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqsehttp_la-http.lo -MD -MP -MF $(DEPDIR)/libqsehttp_la-http.Tpo -c -o libqsehttp_la-http.lo `test -f 'http.c' || echo '$(srcdir)/'`http.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsehttp_la-http.Tpo $(DEPDIR)/libqsehttp_la-http.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http.c' object='libqsehttp_la-http.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqsehttp_la-http.lo `test -f 'http.c' || echo '$(srcdir)/'`http.c
|
||||
|
||||
libqsehttp_la-htre.lo: htre.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqsehttp_la-htre.lo -MD -MP -MF $(DEPDIR)/libqsehttp_la-htre.Tpo -c -o libqsehttp_la-htre.lo `test -f 'htre.c' || echo '$(srcdir)/'`htre.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsehttp_la-htre.Tpo $(DEPDIR)/libqsehttp_la-htre.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='htre.c' object='libqsehttp_la-htre.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqsehttp_la-htre.lo `test -f 'htre.c' || echo '$(srcdir)/'`htre.c
|
||||
|
||||
libqsehttp_la-htrd.lo: htrd.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqsehttp_la-htrd.lo -MD -MP -MF $(DEPDIR)/libqsehttp_la-htrd.Tpo -c -o libqsehttp_la-htrd.lo `test -f 'htrd.c' || echo '$(srcdir)/'`htrd.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsehttp_la-htrd.Tpo $(DEPDIR)/libqsehttp_la-htrd.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='htrd.c' object='libqsehttp_la-htrd.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqsehttp_la-htrd.lo `test -f 'htrd.c' || echo '$(srcdir)/'`htrd.c
|
||||
|
||||
libqsehttp_la-httpd.lo: httpd.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqsehttp_la-httpd.lo -MD -MP -MF $(DEPDIR)/libqsehttp_la-httpd.Tpo -c -o libqsehttp_la-httpd.lo `test -f 'httpd.c' || echo '$(srcdir)/'`httpd.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsehttp_la-httpd.Tpo $(DEPDIR)/libqsehttp_la-httpd.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='httpd.c' object='libqsehttp_la-httpd.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqsehttp_la-httpd.lo `test -f 'httpd.c' || echo '$(srcdir)/'`httpd.c
|
||||
|
||||
libqsehttp_la-httpd-cgi.lo: httpd-cgi.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqsehttp_la-httpd-cgi.lo -MD -MP -MF $(DEPDIR)/libqsehttp_la-httpd-cgi.Tpo -c -o libqsehttp_la-httpd-cgi.lo `test -f 'httpd-cgi.c' || echo '$(srcdir)/'`httpd-cgi.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsehttp_la-httpd-cgi.Tpo $(DEPDIR)/libqsehttp_la-httpd-cgi.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='httpd-cgi.c' object='libqsehttp_la-httpd-cgi.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqsehttp_la-httpd-cgi.lo `test -f 'httpd-cgi.c' || echo '$(srcdir)/'`httpd-cgi.c
|
||||
|
||||
libqsehttp_la-httpd-dir.lo: httpd-dir.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqsehttp_la-httpd-dir.lo -MD -MP -MF $(DEPDIR)/libqsehttp_la-httpd-dir.Tpo -c -o libqsehttp_la-httpd-dir.lo `test -f 'httpd-dir.c' || echo '$(srcdir)/'`httpd-dir.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsehttp_la-httpd-dir.Tpo $(DEPDIR)/libqsehttp_la-httpd-dir.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='httpd-dir.c' object='libqsehttp_la-httpd-dir.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqsehttp_la-httpd-dir.lo `test -f 'httpd-dir.c' || echo '$(srcdir)/'`httpd-dir.c
|
||||
|
||||
libqsehttp_la-httpd-file.lo: httpd-file.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqsehttp_la-httpd-file.lo -MD -MP -MF $(DEPDIR)/libqsehttp_la-httpd-file.Tpo -c -o libqsehttp_la-httpd-file.lo `test -f 'httpd-file.c' || echo '$(srcdir)/'`httpd-file.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsehttp_la-httpd-file.Tpo $(DEPDIR)/libqsehttp_la-httpd-file.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='httpd-file.c' object='libqsehttp_la-httpd-file.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqsehttp_la-httpd-file.lo `test -f 'httpd-file.c' || echo '$(srcdir)/'`httpd-file.c
|
||||
|
||||
libqsehttp_la-httpd-proxy.lo: httpd-proxy.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqsehttp_la-httpd-proxy.lo -MD -MP -MF $(DEPDIR)/libqsehttp_la-httpd-proxy.Tpo -c -o libqsehttp_la-httpd-proxy.lo `test -f 'httpd-proxy.c' || echo '$(srcdir)/'`httpd-proxy.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsehttp_la-httpd-proxy.Tpo $(DEPDIR)/libqsehttp_la-httpd-proxy.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='httpd-proxy.c' object='libqsehttp_la-httpd-proxy.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqsehttp_la-httpd-proxy.lo `test -f 'httpd-proxy.c' || echo '$(srcdir)/'`httpd-proxy.c
|
||||
|
||||
libqsehttp_la-httpd-std.lo: httpd-std.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqsehttp_la-httpd-std.lo -MD -MP -MF $(DEPDIR)/libqsehttp_la-httpd-std.Tpo -c -o libqsehttp_la-httpd-std.lo `test -f 'httpd-std.c' || echo '$(srcdir)/'`httpd-std.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsehttp_la-httpd-std.Tpo $(DEPDIR)/libqsehttp_la-httpd-std.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='httpd-std.c' object='libqsehttp_la-httpd-std.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqsehttp_la-httpd-std.lo `test -f 'httpd-std.c' || echo '$(srcdir)/'`httpd-std.c
|
||||
|
||||
libqsehttp_la-httpd-task.lo: httpd-task.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqsehttp_la-httpd-task.lo -MD -MP -MF $(DEPDIR)/libqsehttp_la-httpd-task.Tpo -c -o libqsehttp_la-httpd-task.lo `test -f 'httpd-task.c' || echo '$(srcdir)/'`httpd-task.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsehttp_la-httpd-task.Tpo $(DEPDIR)/libqsehttp_la-httpd-task.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='httpd-task.c' object='libqsehttp_la-httpd-task.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqsehttp_la-httpd-task.lo `test -f 'httpd-task.c' || echo '$(srcdir)/'`httpd-task.c
|
||||
|
||||
libqsehttp_la-httpd-text.lo: httpd-text.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqsehttp_la-httpd-text.lo -MD -MP -MF $(DEPDIR)/libqsehttp_la-httpd-text.Tpo -c -o libqsehttp_la-httpd-text.lo `test -f 'httpd-text.c' || echo '$(srcdir)/'`httpd-text.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsehttp_la-httpd-text.Tpo $(DEPDIR)/libqsehttp_la-httpd-text.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='httpd-text.c' object='libqsehttp_la-httpd-text.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqsehttp_la-httpd-text.lo `test -f 'httpd-text.c' || echo '$(srcdir)/'`httpd-text.c
|
||||
|
||||
libqsehttp_la-upxd.lo: upxd.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqsehttp_la-upxd.lo -MD -MP -MF $(DEPDIR)/libqsehttp_la-upxd.Tpo -c -o libqsehttp_la-upxd.lo `test -f 'upxd.c' || echo '$(srcdir)/'`upxd.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsehttp_la-upxd.Tpo $(DEPDIR)/libqsehttp_la-upxd.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='upxd.c' object='libqsehttp_la-upxd.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqsehttp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqsehttp_la-upxd.lo `test -f 'upxd.c' || echo '$(srcdir)/'`upxd.c
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
ID: $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); mkid -fID $$unique
|
||||
tags: tags-am
|
||||
TAGS: tags
|
||||
|
||||
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
$(am__define_uniq_tagged_files); \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: ctags-am
|
||||
|
||||
CTAGS: ctags
|
||||
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
cscopelist: cscopelist-am
|
||||
|
||||
cscopelist-am: $(am__tagged_files)
|
||||
list='$(am__tagged_files)'; \
|
||||
case "$(srcdir)" in \
|
||||
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
|
||||
*) sdir=$(subdir)/$(srcdir) ;; \
|
||||
esac; \
|
||||
for i in $$list; do \
|
||||
if test -f "$$i"; then \
|
||||
echo "$(subdir)/$$i"; \
|
||||
else \
|
||||
echo "$$sdir/$$i"; \
|
||||
fi; \
|
||||
done >> $(top_builddir)/cscope.files
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(BUILT_SOURCES)
|
||||
$(MAKE) $(AM_MAKEFLAGS) distdir-am
|
||||
|
||||
distdir-am: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(LTLIBRARIES)
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(libdir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
|
||||
mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-htrd.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-htre.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-http.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd-cgi.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd-dir.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd-file.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd-proxy.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd-std.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd-task.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd-text.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-upxd.Plo
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am: install-libLTLIBRARIES
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-htrd.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-htre.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-http.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd-cgi.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd-dir.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd-file.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd-proxy.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd-std.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd-task.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd-text.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-httpd.Plo
|
||||
-rm -f ./$(DEPDIR)/libqsehttp_la-upxd.Plo
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-libLTLIBRARIES
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
|
||||
clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \
|
||||
ctags ctags-am distclean distclean-compile distclean-generic \
|
||||
distclean-libtool distclean-tags distdir dvi dvi-am html \
|
||||
html-am info info-am install install-am install-data \
|
||||
install-data-am install-dvi install-dvi-am install-exec \
|
||||
install-exec-am install-html install-html-am install-info \
|
||||
install-info-am install-libLTLIBRARIES install-man install-pdf \
|
||||
install-pdf-am install-ps install-ps-am install-strip \
|
||||
installcheck installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
1754
lib/http/htrd.c
Normal file
1754
lib/http/htrd.c
Normal file
File diff suppressed because it is too large
Load Diff
320
lib/http/htre.c
Normal file
320
lib/http/htre.c
Normal file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <qse/http/htre.h>
|
||||
#include "../cmn/mem-prv.h"
|
||||
|
||||
static void free_hdrval (qse_htb_t* htb, void* vptr, qse_size_t vlen)
|
||||
{
|
||||
qse_htre_hdrval_t* val;
|
||||
qse_htre_hdrval_t* tmp;
|
||||
|
||||
val = vptr;
|
||||
while (val)
|
||||
{
|
||||
tmp = val;
|
||||
val = val->next;
|
||||
QSE_MMGR_FREE (htb->mmgr, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
int qse_htre_init (qse_htre_t* re, qse_mmgr_t* mmgr)
|
||||
{
|
||||
static qse_htb_style_t style =
|
||||
{
|
||||
{
|
||||
QSE_HTB_COPIER_DEFAULT,
|
||||
QSE_HTB_COPIER_DEFAULT
|
||||
},
|
||||
{
|
||||
QSE_HTB_FREEER_DEFAULT,
|
||||
free_hdrval
|
||||
},
|
||||
QSE_HTB_COMPER_DEFAULT,
|
||||
QSE_HTB_KEEPER_DEFAULT,
|
||||
QSE_HTB_SIZER_DEFAULT,
|
||||
QSE_HTB_HASHER_DEFAULT
|
||||
};
|
||||
|
||||
QSE_MEMSET (re, 0, QSE_SIZEOF(*re));
|
||||
re->mmgr = mmgr;
|
||||
|
||||
if (qse_htb_init (&re->hdrtab, mmgr, 60, 70, 1, 1) <= -1) return -1;
|
||||
if (qse_htb_init (&re->trailers, mmgr, 20, 70, 1, 1) <= -1) return -1;
|
||||
|
||||
qse_htb_setstyle (&re->hdrtab, &style);
|
||||
qse_htb_setstyle (&re->trailers, &style);
|
||||
|
||||
qse_mbs_init (&re->content, mmgr, 0);
|
||||
#if 0
|
||||
qse_mbs_init (&re->iniline, mmgr, 0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qse_htre_fini (qse_htre_t* re)
|
||||
{
|
||||
#if 0
|
||||
qse_mbs_fini (&re->iniline);
|
||||
#endif
|
||||
qse_mbs_fini (&re->content);
|
||||
qse_htb_fini (&re->trailers);
|
||||
qse_htb_fini (&re->hdrtab);
|
||||
|
||||
if (re->orgqpath.buf)
|
||||
QSE_MMGR_FREE (re->mmgr, re->orgqpath.buf);
|
||||
}
|
||||
|
||||
void qse_htre_clear (qse_htre_t* re)
|
||||
{
|
||||
if (!(re->state & QSE_HTRE_COMPLETED) &&
|
||||
!(re->state & QSE_HTRE_DISCARDED))
|
||||
{
|
||||
if (re->concb)
|
||||
{
|
||||
re->concb (re, QSE_NULL, 0, re->concb_ctx); /* indicate end of content */
|
||||
qse_htre_unsetconcb (re);
|
||||
}
|
||||
}
|
||||
|
||||
re->state = 0;
|
||||
re->flags = 0;
|
||||
|
||||
re->orgqpath.ptr = QSE_NULL;
|
||||
re->orgqpath.len = 0;
|
||||
|
||||
QSE_MEMSET (&re->version, 0, QSE_SIZEOF(re->version));
|
||||
QSE_MEMSET (&re->attr, 0, QSE_SIZEOF(re->attr));
|
||||
|
||||
qse_htb_clear (&re->hdrtab);
|
||||
qse_htb_clear (&re->trailers);
|
||||
|
||||
qse_mbs_clear (&re->content);
|
||||
#if 0
|
||||
qse_mbs_clear (&re->iniline);
|
||||
#endif
|
||||
}
|
||||
|
||||
const qse_htre_hdrval_t* qse_htre_getheaderval (
|
||||
const qse_htre_t* re, const qse_mchar_t* name)
|
||||
{
|
||||
qse_htb_pair_t* pair;
|
||||
pair = qse_htb_search (&re->hdrtab, name, qse_mbslen(name));
|
||||
if (pair == QSE_NULL) return QSE_NULL;
|
||||
return QSE_HTB_VPTR(pair);
|
||||
}
|
||||
|
||||
const qse_htre_hdrval_t* qse_htre_gettrailerval (
|
||||
const qse_htre_t* re, const qse_mchar_t* name)
|
||||
{
|
||||
qse_htb_pair_t* pair;
|
||||
pair = qse_htb_search (&re->trailers, name, qse_mbslen(name));
|
||||
if (pair == QSE_NULL) return QSE_NULL;
|
||||
return QSE_HTB_VPTR(pair);
|
||||
}
|
||||
|
||||
struct header_walker_ctx_t
|
||||
{
|
||||
qse_htre_t* re;
|
||||
qse_htre_header_walker_t walker;
|
||||
void* ctx;
|
||||
int ret;
|
||||
};
|
||||
|
||||
static qse_htb_walk_t walk_headers (
|
||||
qse_htb_t* htb, qse_htb_pair_t* pair, void* ctx)
|
||||
{
|
||||
struct header_walker_ctx_t* hwctx = (struct header_walker_ctx_t*)ctx;
|
||||
if (hwctx->walker (hwctx->re, QSE_HTB_KPTR(pair), QSE_HTB_VPTR(pair), hwctx->ctx) <= -1)
|
||||
{
|
||||
hwctx->ret = -1;
|
||||
return QSE_HTB_WALK_STOP;
|
||||
}
|
||||
return QSE_HTB_WALK_FORWARD;
|
||||
}
|
||||
|
||||
int qse_htre_walkheaders (
|
||||
qse_htre_t* re, qse_htre_header_walker_t walker, void* ctx)
|
||||
{
|
||||
struct header_walker_ctx_t hwctx;
|
||||
hwctx.re = re;
|
||||
hwctx.walker = walker;
|
||||
hwctx.ctx = ctx;
|
||||
hwctx.ret = 0;
|
||||
qse_htb_walk (&re->hdrtab, walk_headers, &hwctx);
|
||||
return hwctx.ret;
|
||||
}
|
||||
|
||||
int qse_htre_walktrailers (
|
||||
qse_htre_t* re, qse_htre_header_walker_t walker, void* ctx)
|
||||
{
|
||||
struct header_walker_ctx_t hwctx;
|
||||
hwctx.re = re;
|
||||
hwctx.walker = walker;
|
||||
hwctx.ctx = ctx;
|
||||
hwctx.ret = 0;
|
||||
qse_htb_walk (&re->trailers, walk_headers, &hwctx);
|
||||
return hwctx.ret;
|
||||
}
|
||||
|
||||
int qse_htre_addcontent (
|
||||
qse_htre_t* re, const qse_mchar_t* ptr, qse_size_t len)
|
||||
{
|
||||
/* see comments in qse_htre_discardcontent() */
|
||||
|
||||
if (re->state & (QSE_HTRE_COMPLETED | QSE_HTRE_DISCARDED)) return 0; /* skipped */
|
||||
|
||||
if (re->concb)
|
||||
{
|
||||
/* if the callback is set, the content goes to the callback. */
|
||||
if (re->concb (re, ptr, len, re->concb_ctx) <= -1) return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if the callback is not set, the contents goes to the internal buffer */
|
||||
if (qse_mbs_ncat (&re->content, ptr, len) == (qse_size_t)-1) return -1;
|
||||
}
|
||||
|
||||
return 1; /* added successfully */
|
||||
}
|
||||
|
||||
void qse_htre_completecontent (qse_htre_t* re)
|
||||
{
|
||||
/* see comments in qse_htre_discardcontent() */
|
||||
|
||||
if (!(re->state & QSE_HTRE_COMPLETED) &&
|
||||
!(re->state & QSE_HTRE_DISCARDED))
|
||||
{
|
||||
re->state |= QSE_HTRE_COMPLETED;
|
||||
if (re->concb)
|
||||
{
|
||||
/* indicate end of content */
|
||||
re->concb (re, QSE_NULL, 0, re->concb_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void qse_htre_discardcontent (qse_htre_t* re)
|
||||
{
|
||||
/* you can't discard this if it's completed.
|
||||
* you can't complete this if it's discarded
|
||||
* you can't add contents to this if it's completed or discarded
|
||||
*/
|
||||
|
||||
if (!(re->state & QSE_HTRE_COMPLETED) &&
|
||||
!(re->state & QSE_HTRE_DISCARDED))
|
||||
{
|
||||
re->state |= QSE_HTRE_DISCARDED;
|
||||
|
||||
/* qse_htre_addcontent()...
|
||||
* qse_thre_setconcb()...
|
||||
* qse_htre_discardcontent()... <-- POINT A.
|
||||
*
|
||||
* at point A, the content must contain something
|
||||
* and concb is also set. for simplicity,
|
||||
* clear the content buffer and invoke the callback
|
||||
*
|
||||
* likewise, you may produce many weird combinations
|
||||
* of these functions. however, these functions are
|
||||
* designed to serve a certain usage pattern not including
|
||||
* weird combinations.
|
||||
*/
|
||||
qse_mbs_clear (&re->content);
|
||||
if (re->concb)
|
||||
{
|
||||
/* indicate end of content */
|
||||
re->concb (re, QSE_NULL, 0, re->concb_ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void qse_htre_unsetconcb (qse_htre_t* re)
|
||||
{
|
||||
re->concb = QSE_NULL;
|
||||
re->concb_ctx = QSE_NULL;
|
||||
}
|
||||
|
||||
void qse_htre_setconcb (qse_htre_t* re, qse_htre_concb_t concb, void* ctx)
|
||||
{
|
||||
re->concb = concb;
|
||||
re->concb_ctx = ctx;
|
||||
}
|
||||
|
||||
int qse_htre_perdecqpath (qse_htre_t* re)
|
||||
{
|
||||
qse_size_t dec_count;
|
||||
|
||||
/* percent decode the query path*/
|
||||
|
||||
if (re->type != QSE_HTRE_Q || (re->flags & QSE_HTRE_QPATH_PERDEC)) return -1;
|
||||
|
||||
QSE_ASSERT (re->orgqpath.len <= 0);
|
||||
QSE_ASSERT (re->orgqpath.ptr == QSE_NULL);
|
||||
|
||||
if (qse_isperencedhttpstr(re->u.q.path.ptr))
|
||||
{
|
||||
/* the string is percent-encoded. keep the original request
|
||||
* in a separately allocated buffer */
|
||||
|
||||
if (re->orgqpath.buf && re->u.q.path.len <= re->orgqpath.capa)
|
||||
{
|
||||
re->orgqpath.len = qse_mbscpy (re->orgqpath.buf, re->u.q.path.ptr);
|
||||
re->orgqpath.ptr = re->orgqpath.buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (re->orgqpath.buf)
|
||||
{
|
||||
QSE_MMGR_FREE (re->mmgr, re->orgqpath.buf);
|
||||
re->orgqpath.capa = 0;
|
||||
}
|
||||
|
||||
re->orgqpath.buf = qse_mbsxdup (re->u.q.path.ptr, re->u.q.path.len, re->mmgr);
|
||||
if (!re->orgqpath.buf) return -1;
|
||||
re->orgqpath.capa = re->u.q.path.len;
|
||||
|
||||
re->orgqpath.ptr = re->orgqpath.buf;
|
||||
re->orgqpath.len = re->orgqpath.capa;
|
||||
|
||||
/* orgqpath.buf and orgqpath.ptr are the same here. the caller
|
||||
* is free to change orgqpath.ptr to point to a differnt position
|
||||
* in the buffer. */
|
||||
}
|
||||
}
|
||||
|
||||
re->u.q.path.len = qse_perdechttpstr (re->u.q.path.ptr, re->u.q.path.ptr, &dec_count);
|
||||
if (dec_count > 0)
|
||||
{
|
||||
/* this assertion is to ensure that qse_isperencedhttpstr()
|
||||
* returned true when dec_count is greater than 0 */
|
||||
QSE_ASSERT (re->orgqpath.buf != QSE_NULL);
|
||||
QSE_ASSERT (re->orgqpath.ptr != QSE_NULL);
|
||||
re->flags |= QSE_HTRE_QPATH_PERDEC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
540
lib/http/http.c
Normal file
540
lib/http/http.c
Normal file
@ -0,0 +1,540 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <qse/http/http.h>
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/chr.h>
|
||||
#include <qse/cmn/htb.h>
|
||||
#include "../cmn/mem-prv.h"
|
||||
|
||||
int qse_comparehttpversions (
|
||||
const qse_http_version_t* v1,
|
||||
const qse_http_version_t* v2)
|
||||
{
|
||||
if (v1->major == v2->major) return v1->minor - v2->minor;
|
||||
return v1->major - v2->major;
|
||||
}
|
||||
|
||||
const qse_mchar_t* qse_httpstatustombs (int code)
|
||||
{
|
||||
const qse_mchar_t* msg;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case 100: msg = QSE_MT("Continue"); break;
|
||||
case 101: msg = QSE_MT("Switching Protocols"); break;
|
||||
|
||||
case 200: msg = QSE_MT("OK"); break;
|
||||
case 201: msg = QSE_MT("Created"); break;
|
||||
case 202: msg = QSE_MT("Accepted"); break;
|
||||
case 203: msg = QSE_MT("Non-Authoritative Information"); break;
|
||||
case 204: msg = QSE_MT("No Content"); break;
|
||||
case 205: msg = QSE_MT("Reset Content"); break;
|
||||
case 206: msg = QSE_MT("Partial Content"); break;
|
||||
|
||||
case 300: msg = QSE_MT("Multiple Choices"); break;
|
||||
case 301: msg = QSE_MT("Moved Permanently"); break;
|
||||
case 302: msg = QSE_MT("Found"); break;
|
||||
case 303: msg = QSE_MT("See Other"); break;
|
||||
case 304: msg = QSE_MT("Not Modified"); break;
|
||||
case 305: msg = QSE_MT("Use Proxy"); break;
|
||||
case 307: msg = QSE_MT("Temporary Redirect"); break;
|
||||
case 308: msg = QSE_MT("Permanent Redirect"); break;
|
||||
|
||||
case 400: msg = QSE_MT("Bad Request"); break;
|
||||
case 401: msg = QSE_MT("Unauthorized"); break;
|
||||
case 402: msg = QSE_MT("Payment Required"); break;
|
||||
case 403: msg = QSE_MT("Forbidden"); break;
|
||||
case 404: msg = QSE_MT("Not Found"); break;
|
||||
case 405: msg = QSE_MT("Method Not Allowed"); break;
|
||||
case 406: msg = QSE_MT("Not Acceptable"); break;
|
||||
case 407: msg = QSE_MT("Proxy Authentication Required"); break;
|
||||
case 408: msg = QSE_MT("Request Timeout"); break;
|
||||
case 409: msg = QSE_MT("Conflict"); break;
|
||||
case 410: msg = QSE_MT("Gone"); break;
|
||||
case 411: msg = QSE_MT("Length Required"); break;
|
||||
case 412: msg = QSE_MT("Precondition Failed"); break;
|
||||
case 413: msg = QSE_MT("Request Entity Too Large"); break;
|
||||
case 414: msg = QSE_MT("Request-URI Too Long"); break;
|
||||
case 415: msg = QSE_MT("Unsupported Media Type"); break;
|
||||
case 416: msg = QSE_MT("Requested Range Not Satisfiable"); break;
|
||||
case 417: msg = QSE_MT("Expectation Failed"); break;
|
||||
case 426: msg = QSE_MT("Upgrade Required"); break;
|
||||
case 428: msg = QSE_MT("Precondition Required"); break;
|
||||
case 429: msg = QSE_MT("Too Many Requests"); break;
|
||||
case 431: msg = QSE_MT("Request Header Fields Too Large"); break;
|
||||
|
||||
case 500: msg = QSE_MT("Internal Server Error"); break;
|
||||
case 501: msg = QSE_MT("Not Implemented"); break;
|
||||
case 502: msg = QSE_MT("Bad Gateway"); break;
|
||||
case 503: msg = QSE_MT("Service Unavailable"); break;
|
||||
case 504: msg = QSE_MT("Gateway Timeout"); break;
|
||||
case 505: msg = QSE_MT("HTTP Version Not Supported"); break;
|
||||
|
||||
default: msg = QSE_MT("Unknown Error"); break;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
const qse_mchar_t* qse_httpmethodtombs (qse_http_method_t type)
|
||||
{
|
||||
/* keep this table in the same order as qse_httpd_method_t enumerators */
|
||||
static qse_mchar_t* names[] =
|
||||
{
|
||||
QSE_MT("OTHER"),
|
||||
|
||||
QSE_MT("HEAD"),
|
||||
QSE_MT("GET"),
|
||||
QSE_MT("POST"),
|
||||
QSE_MT("PUT"),
|
||||
QSE_MT("DELETE"),
|
||||
QSE_MT("OPTIONS"),
|
||||
QSE_MT("TRACE"),
|
||||
QSE_MT("CONNECT")
|
||||
};
|
||||
|
||||
return (type < 0 || type >= QSE_COUNTOF(names))? QSE_NULL: names[type];
|
||||
}
|
||||
|
||||
struct mtab_t
|
||||
{
|
||||
const qse_mchar_t* name;
|
||||
qse_http_method_t type;
|
||||
};
|
||||
|
||||
static struct mtab_t mtab[] =
|
||||
{
|
||||
/* keep this table sorted by name for binary search */
|
||||
{ QSE_MT("CONNECT"), QSE_HTTP_CONNECT },
|
||||
{ QSE_MT("DELETE"), QSE_HTTP_DELETE },
|
||||
{ QSE_MT("GET"), QSE_HTTP_GET },
|
||||
{ QSE_MT("HEAD"), QSE_HTTP_HEAD },
|
||||
{ QSE_MT("OPTIONS"), QSE_HTTP_OPTIONS },
|
||||
{ QSE_MT("POST"), QSE_HTTP_POST },
|
||||
{ QSE_MT("PUT"), QSE_HTTP_PUT },
|
||||
{ QSE_MT("TRACE"), QSE_HTTP_TRACE }
|
||||
};
|
||||
|
||||
qse_http_method_t qse_mbstohttpmethod (const qse_mchar_t* name)
|
||||
{
|
||||
/* perform binary search */
|
||||
|
||||
/* declaring left, right, mid to be of int is ok
|
||||
* because we know mtab is small enough. */
|
||||
int left = 0, right = QSE_COUNTOF(mtab) - 1, mid;
|
||||
|
||||
while (left <= right)
|
||||
{
|
||||
int n;
|
||||
struct mtab_t* entry;
|
||||
|
||||
/*mid = (left + right) / 2;*/
|
||||
mid = left + (right - left) / 2;
|
||||
entry = &mtab[mid];
|
||||
|
||||
n = qse_mbscmp (name, entry->name);
|
||||
if (n < 0)
|
||||
{
|
||||
/* if left, right, mid were of qse_size_t,
|
||||
* you would need the following line.
|
||||
if (mid == 0) break;
|
||||
*/
|
||||
right = mid - 1;
|
||||
}
|
||||
else if (n > 0) left = mid + 1;
|
||||
else return entry->type;
|
||||
}
|
||||
|
||||
return QSE_HTTP_OTHER;
|
||||
}
|
||||
|
||||
qse_http_method_t qse_mcstrtohttpmethod (const qse_mcstr_t* name)
|
||||
{
|
||||
/* perform binary search */
|
||||
|
||||
/* declaring left, right, mid to be of int is ok
|
||||
* because we know mtab is small enough. */
|
||||
int left = 0, right = QSE_COUNTOF(mtab) - 1, mid;
|
||||
|
||||
while (left <= right)
|
||||
{
|
||||
int n;
|
||||
struct mtab_t* entry;
|
||||
|
||||
/*mid = (left + right) / 2;*/
|
||||
mid = left + (right - left) / 2;
|
||||
entry = &mtab[mid];
|
||||
|
||||
n = qse_mbsxcmp (name->ptr, name->len, entry->name);
|
||||
if (n < 0)
|
||||
{
|
||||
/* if left, right, mid were of qse_size_t,
|
||||
* you would need the following line.
|
||||
if (mid == 0) break;
|
||||
*/
|
||||
right = mid - 1;
|
||||
}
|
||||
else if (n > 0) left = mid + 1;
|
||||
else return entry->type;
|
||||
}
|
||||
|
||||
return QSE_HTTP_OTHER;
|
||||
}
|
||||
|
||||
int qse_parsehttprange (const qse_mchar_t* str, qse_http_range_t* range)
|
||||
{
|
||||
/* NOTE: this function does not support a range set
|
||||
* like bytes=1-20,30-50 */
|
||||
|
||||
qse_http_range_int_t from, to;
|
||||
int type = QSE_HTTP_RANGE_PROPER;
|
||||
|
||||
if (str[0] != QSE_MT('b') ||
|
||||
str[1] != QSE_MT('y') ||
|
||||
str[2] != QSE_MT('t') ||
|
||||
str[3] != QSE_MT('e') ||
|
||||
str[4] != QSE_MT('s') ||
|
||||
str[5] != QSE_MT('=')) return -1;
|
||||
|
||||
str += 6;
|
||||
|
||||
from = 0;
|
||||
if (QSE_ISMDIGIT(*str))
|
||||
{
|
||||
do
|
||||
{
|
||||
from = from * 10 + (*str - QSE_MT('0'));
|
||||
str++;
|
||||
}
|
||||
while (QSE_ISMDIGIT(*str));
|
||||
}
|
||||
else type = QSE_HTTP_RANGE_SUFFIX;
|
||||
|
||||
if (*str != QSE_MT('-')) return -1;
|
||||
str++;
|
||||
|
||||
if (QSE_ISMDIGIT(*str))
|
||||
{
|
||||
to = 0;
|
||||
do
|
||||
{
|
||||
to = to * 10 + (*str - QSE_MT('0'));
|
||||
str++;
|
||||
}
|
||||
while (QSE_ISMDIGIT(*str));
|
||||
}
|
||||
else to = QSE_TYPE_MAX(qse_http_range_int_t);
|
||||
|
||||
if (from > to) return -1;
|
||||
|
||||
range->type = type;
|
||||
range->from = from;
|
||||
range->to = to;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct mname_t mname_t;
|
||||
struct mname_t
|
||||
{
|
||||
const qse_mchar_t* s;
|
||||
const qse_mchar_t* l;
|
||||
};
|
||||
|
||||
static mname_t wday_name[] =
|
||||
{
|
||||
{ QSE_MT("Sun"), QSE_MT("Sunday") },
|
||||
{ QSE_MT("Mon"), QSE_MT("Monday") },
|
||||
{ QSE_MT("Tue"), QSE_MT("Tuesday") },
|
||||
{ QSE_MT("Wed"), QSE_MT("Wednesday") },
|
||||
{ QSE_MT("Thu"), QSE_MT("Thursday") },
|
||||
{ QSE_MT("Fri"), QSE_MT("Friday") },
|
||||
{ QSE_MT("Sat"), QSE_MT("Saturday") }
|
||||
};
|
||||
|
||||
static mname_t mon_name[] =
|
||||
{
|
||||
{ QSE_MT("Jan"), QSE_MT("January") },
|
||||
{ QSE_MT("Feb"), QSE_MT("February") },
|
||||
{ QSE_MT("Mar"), QSE_MT("March") },
|
||||
{ QSE_MT("Apr"), QSE_MT("April") },
|
||||
{ QSE_MT("May"), QSE_MT("May") },
|
||||
{ QSE_MT("Jun"), QSE_MT("June") },
|
||||
{ QSE_MT("Jul"), QSE_MT("July") },
|
||||
{ QSE_MT("Aug"), QSE_MT("August") },
|
||||
{ QSE_MT("Sep"), QSE_MT("September") },
|
||||
{ QSE_MT("Oct"), QSE_MT("October") },
|
||||
{ QSE_MT("Nov"), QSE_MT("November") },
|
||||
{ QSE_MT("Dec"), QSE_MT("December") }
|
||||
};
|
||||
|
||||
int qse_parsehttptime (const qse_mchar_t* str, qse_ntime_t* nt)
|
||||
{
|
||||
qse_btime_t bt;
|
||||
const qse_mchar_t* word;
|
||||
qse_size_t wlen, i;
|
||||
|
||||
/* TODO: support more formats */
|
||||
|
||||
QSE_MEMSET (&bt, 0, QSE_SIZEOF(bt));
|
||||
|
||||
/* weekday */
|
||||
while (QSE_ISMSPACE(*str)) str++;
|
||||
for (word = str; QSE_ISMALPHA(*str); str++);
|
||||
wlen = str - word;
|
||||
for (i = 0; i < QSE_COUNTOF(wday_name); i++)
|
||||
{
|
||||
if (qse_mbsxcmp (word, wlen, wday_name[i].s) == 0)
|
||||
{
|
||||
bt.wday = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= QSE_COUNTOF(wday_name)) return -1;
|
||||
|
||||
/* comma - i'm just loose as i don't care if it doesn't exist */
|
||||
while (QSE_ISMSPACE(*str)) str++;
|
||||
if (*str == QSE_MT(',')) str++;
|
||||
|
||||
/* day */
|
||||
while (QSE_ISMSPACE(*str)) str++;
|
||||
if (!QSE_ISMDIGIT(*str)) return -1;
|
||||
do bt.mday = bt.mday * 10 + *str++ - QSE_MT('0'); while (QSE_ISMDIGIT(*str));
|
||||
|
||||
/* month */
|
||||
while (QSE_ISMSPACE(*str)) str++;
|
||||
for (word = str; QSE_ISMALPHA(*str); str++);
|
||||
wlen = str - word;
|
||||
for (i = 0; i < QSE_COUNTOF(mon_name); i++)
|
||||
{
|
||||
if (qse_mbsxcmp (word, wlen, mon_name[i].s) == 0)
|
||||
{
|
||||
bt.mon = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= QSE_COUNTOF(mon_name)) return -1;
|
||||
|
||||
/* year */
|
||||
while (QSE_ISMSPACE(*str)) str++;
|
||||
if (!QSE_ISMDIGIT(*str)) return -1;
|
||||
do bt.year = bt.year * 10 + *str++ - QSE_MT('0'); while (QSE_ISMDIGIT(*str));
|
||||
bt.year -= QSE_BTIME_YEAR_BASE;
|
||||
|
||||
/* hour */
|
||||
while (QSE_ISMSPACE(*str)) str++;
|
||||
if (!QSE_ISMDIGIT(*str)) return -1;
|
||||
do bt.hour = bt.hour * 10 + *str++ - QSE_MT('0'); while (QSE_ISMDIGIT(*str));
|
||||
if (*str != QSE_MT(':')) return -1;
|
||||
str++;
|
||||
|
||||
/* min */
|
||||
while (QSE_ISMSPACE(*str)) str++;
|
||||
if (!QSE_ISMDIGIT(*str)) return -1;
|
||||
do bt.min = bt.min * 10 + *str++ - QSE_MT('0'); while (QSE_ISMDIGIT(*str));
|
||||
if (*str != QSE_MT(':')) return -1;
|
||||
str++;
|
||||
|
||||
/* sec */
|
||||
while (QSE_ISMSPACE(*str)) str++;
|
||||
if (!QSE_ISMDIGIT(*str)) return -1;
|
||||
do bt.sec = bt.sec * 10 + *str++ - QSE_MT('0'); while (QSE_ISMDIGIT(*str));
|
||||
|
||||
/* GMT */
|
||||
while (QSE_ISMSPACE(*str)) str++;
|
||||
for (word = str; QSE_ISMALPHA(*str); str++);
|
||||
wlen = str - word;
|
||||
if (qse_mbsxcmp (word, wlen, QSE_MT("GMT")) != 0) return -1;
|
||||
|
||||
while (QSE_ISMSPACE(*str)) str++;
|
||||
if (*str != QSE_MT('\0')) return -1;
|
||||
|
||||
return qse_timegm (&bt, nt);
|
||||
}
|
||||
|
||||
qse_mchar_t* qse_fmthttptime (
|
||||
const qse_ntime_t* nt, qse_mchar_t* buf, qse_size_t bufsz)
|
||||
{
|
||||
qse_btime_t bt;
|
||||
|
||||
qse_gmtime (nt, &bt);
|
||||
|
||||
qse_mbsxfmt (
|
||||
buf, bufsz,
|
||||
QSE_MT("%s, %d %s %d %02d:%02d:%02d GMT"),
|
||||
wday_name[bt.wday].s,
|
||||
bt.mday,
|
||||
mon_name[bt.mon].s,
|
||||
bt.year + QSE_BTIME_YEAR_BASE,
|
||||
bt.hour, bt.min, bt.sec
|
||||
);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
int qse_isperencedhttpstr (const qse_mchar_t* str)
|
||||
{
|
||||
const qse_mchar_t* p = str;
|
||||
|
||||
while (*p != QSE_MT('\0'))
|
||||
{
|
||||
if (*p == QSE_MT('%') && *(p + 1) != QSE_MT('\0') && *(p + 2) != QSE_MT('\0'))
|
||||
{
|
||||
int q = QSE_MXDIGITTONUM (*(p + 1));
|
||||
if (q >= 0)
|
||||
{
|
||||
/* return true if the first valid percent-encoded sequence is found */
|
||||
int w = QSE_MXDIGITTONUM (*(p + 2));
|
||||
if (w >= 0) return 1;
|
||||
}
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
qse_size_t qse_perdechttpstr (const qse_mchar_t* str, qse_mchar_t* buf, qse_size_t* ndecs)
|
||||
{
|
||||
const qse_mchar_t* p = str;
|
||||
qse_mchar_t* out = buf;
|
||||
qse_size_t dec_count = 0;
|
||||
|
||||
while (*p != QSE_MT('\0'))
|
||||
{
|
||||
if (*p == QSE_MT('%') && *(p + 1) != QSE_MT('\0') && *(p + 2) != QSE_MT('\0'))
|
||||
{
|
||||
int q = QSE_MXDIGITTONUM (*(p + 1));
|
||||
if (q >= 0)
|
||||
{
|
||||
int w = QSE_MXDIGITTONUM (*(p + 2));
|
||||
if (w >= 0)
|
||||
{
|
||||
/* we don't care if it contains a null character */
|
||||
*out++ = ((q << 4) + w);
|
||||
p += 3;
|
||||
dec_count++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*out++ = *p++;
|
||||
}
|
||||
|
||||
*out = QSE_MT('\0');
|
||||
if (ndecs) *ndecs = dec_count;
|
||||
return out - buf;
|
||||
}
|
||||
|
||||
#define IS_UNRESERVED(c) \
|
||||
(((c) >= QSE_MT('A') && (c) <= QSE_MT('Z')) || \
|
||||
((c) >= QSE_MT('a') && (c) <= QSE_MT('z')) || \
|
||||
((c) >= QSE_MT('0') && (c) <= QSE_MT('9')) || \
|
||||
(c) == QSE_MT('-') || (c) == QSE_MT('_') || \
|
||||
(c) == QSE_MT('.') || (c) == QSE_MT('~'))
|
||||
|
||||
#define TO_HEX(v) (QSE_MT("0123456789ABCDEF")[(v) & 15])
|
||||
|
||||
qse_size_t qse_perenchttpstr (int opt, const qse_mchar_t* str, qse_mchar_t* buf, qse_size_t* nencs)
|
||||
{
|
||||
const qse_mchar_t* p = str;
|
||||
qse_mchar_t* out = buf;
|
||||
qse_size_t enc_count = 0;
|
||||
|
||||
/* this function doesn't accept the size of the buffer. the caller must
|
||||
* ensure that the buffer is large enough */
|
||||
|
||||
if (opt & QSE_PERENCHTTPSTR_KEEP_SLASH)
|
||||
{
|
||||
while (*p != QSE_MT('\0'))
|
||||
{
|
||||
if (IS_UNRESERVED(*p) || *p == QSE_MT('/')) *out++ = *p;
|
||||
else
|
||||
{
|
||||
*out++ = QSE_MT('%');
|
||||
*out++ = TO_HEX (*p >> 4);
|
||||
*out++ = TO_HEX (*p & 15);
|
||||
enc_count++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (*p != QSE_MT('\0'))
|
||||
{
|
||||
if (IS_UNRESERVED(*p)) *out++ = *p;
|
||||
else
|
||||
{
|
||||
*out++ = QSE_MT('%');
|
||||
*out++ = TO_HEX (*p >> 4);
|
||||
*out++ = TO_HEX (*p & 15);
|
||||
enc_count++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
*out = QSE_MT('\0');
|
||||
if (nencs) *nencs = enc_count;
|
||||
return out - buf;
|
||||
}
|
||||
|
||||
qse_mchar_t* qse_perenchttpstrdup (int opt, const qse_mchar_t* str, qse_mmgr_t* mmgr)
|
||||
{
|
||||
qse_mchar_t* buf;
|
||||
qse_size_t len = 0;
|
||||
qse_size_t count = 0;
|
||||
|
||||
/* count the number of characters that should be encoded */
|
||||
if (opt & QSE_PERENCHTTPSTR_KEEP_SLASH)
|
||||
{
|
||||
for (len = 0; str[len] != QSE_MT('\0'); len++)
|
||||
{
|
||||
if (!IS_UNRESERVED(str[len]) && str[len] != QSE_MT('/')) count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (len = 0; str[len] != QSE_MT('\0'); len++)
|
||||
{
|
||||
if (!IS_UNRESERVED(str[len])) count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* if there are no characters to escape, just return the original string */
|
||||
if (count <= 0) return (qse_mchar_t*)str;
|
||||
|
||||
/* allocate a buffer of an optimal size for escaping, otherwise */
|
||||
buf = QSE_MMGR_ALLOC (mmgr, (len + (count * 2) + 1) * QSE_SIZEOF(*buf));
|
||||
if (buf == QSE_NULL) return QSE_NULL;
|
||||
|
||||
/* perform actual escaping */
|
||||
qse_perenchttpstr (opt, str, buf, QSE_NULL);
|
||||
|
||||
return buf;
|
||||
}
|
1683
lib/http/httpd-cgi.c
Normal file
1683
lib/http/httpd-cgi.c
Normal file
File diff suppressed because it is too large
Load Diff
689
lib/http/httpd-dir.c
Normal file
689
lib/http/httpd-dir.c
Normal file
@ -0,0 +1,689 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "httpd.h"
|
||||
#include "../cmn/mem-prv.h"
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/fmt.h>
|
||||
|
||||
typedef struct task_dir_t task_dir_t;
|
||||
struct task_dir_t
|
||||
{
|
||||
qse_mcstr_t path;
|
||||
qse_mcstr_t qpath;
|
||||
qse_mcstr_t head;
|
||||
qse_mcstr_t foot;
|
||||
qse_http_version_t version;
|
||||
int keepalive;
|
||||
int method;
|
||||
qse_httpd_hnd_t handle;
|
||||
};
|
||||
|
||||
typedef struct task_dseg_t task_dseg_t;
|
||||
struct task_dseg_t
|
||||
{
|
||||
qse_http_version_t version;
|
||||
int keepalive;
|
||||
int chunked;
|
||||
|
||||
qse_mcstr_t path;
|
||||
qse_mcstr_t qpath;
|
||||
qse_mcstr_t head;
|
||||
qse_mcstr_t foot;
|
||||
qse_httpd_hnd_t handle;
|
||||
qse_httpd_dirent_t dent;
|
||||
|
||||
#define HEADER_ADDED (1 << 0)
|
||||
#define FOOTER_ADDED (1 << 1)
|
||||
#define FOOTER_PENDING (1 << 2)
|
||||
#define DIRENT_PENDING (1 << 3)
|
||||
#define DIRENT_NOMORE (1 << 4)
|
||||
int state;
|
||||
|
||||
qse_size_t tcount; /* total directory entries */
|
||||
qse_size_t dcount; /* the number of items in the buffer */
|
||||
|
||||
qse_mchar_t buf[4096*2]; /* is this large enough? */
|
||||
int bufpos;
|
||||
int buflen;
|
||||
int bufrem;
|
||||
qse_size_t chunklen;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
xtn->head.ptr = xtn->qpath.ptr + xtn->qpath.len + 1;
|
||||
qse_mbscpy ((qse_mchar_t*)xtn->head.ptr, arg->head.ptr);
|
||||
xtn->foot.ptr = xtn->head.ptr + xtn->head.len + 1;
|
||||
qse_mbscpy ((qse_mchar_t*)xtn->foot.ptr, arg->foot.ptr);
|
||||
|
||||
task->ctx = xtn;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void task_fini_dseg (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_dseg_t* ctx = (task_dseg_t*)task->ctx;
|
||||
httpd->opt.scb.dir.close (httpd, ctx->handle);
|
||||
}
|
||||
|
||||
#define SIZE_CHLEN 4 /* the space size to hold the hexadecimal chunk length */
|
||||
#define SIZE_CHLENCRLF 2 /* the space size to hold CRLF after the chunk length */
|
||||
#define SIZE_CHENDCRLF 2 /* the sapce size to hold CRLF after the chunk data */
|
||||
|
||||
static QSE_INLINE void close_chunk_data (task_dseg_t* ctx, qse_size_t len)
|
||||
{
|
||||
ctx->chunklen = len;
|
||||
|
||||
/* CHENDCRLF - there is always space for these two.
|
||||
* reserved with SIZE_CHENDCRLF */
|
||||
ctx->buf[ctx->buflen++] = QSE_MT('\r');
|
||||
ctx->buf[ctx->buflen++] = QSE_MT('\n');
|
||||
}
|
||||
|
||||
static void fill_chunk_length (task_dseg_t* ctx)
|
||||
{
|
||||
int x;
|
||||
|
||||
/* right alignment with space padding on the left */
|
||||
x = qse_fmtuintmaxtombs (
|
||||
ctx->buf, (SIZE_CHLEN + SIZE_CHLENCRLF) - 1,
|
||||
(ctx->chunklen - (SIZE_CHLEN + SIZE_CHLENCRLF)), /* value to convert */
|
||||
16 | QSE_FMTUINTMAXTOMBS_UPPERCASE, /* uppercase hexadecimal letters */
|
||||
-1, /* no particular precision - want space filled if less than 4 digits */
|
||||
QSE_MT(' '), /* fill with space */
|
||||
QSE_NULL
|
||||
);
|
||||
/* i don't check the buffer size error because i've secured the
|
||||
* suffient space for the chunk length at the beginning of the buffer */
|
||||
|
||||
/* CHLENCRLF */
|
||||
ctx->buf[x] = QSE_MT('\r');
|
||||
ctx->buf[x+1] = QSE_MT('\n');
|
||||
|
||||
/* skip leading space padding */
|
||||
QSE_ASSERT (ctx->bufpos == 0);
|
||||
while (ctx->buf[ctx->bufpos] == QSE_MT(' ')) ctx->bufpos++;
|
||||
}
|
||||
|
||||
static qse_size_t format_dirent (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
const qse_httpd_dirent_t* dirent,
|
||||
qse_mchar_t* buf, int bufsz)
|
||||
{
|
||||
qse_size_t x;
|
||||
|
||||
qse_mchar_t* encname;
|
||||
qse_mchar_t* escname;
|
||||
qse_btime_t bt;
|
||||
qse_mchar_t tmbuf[32];
|
||||
qse_mchar_t fszbuf[64];
|
||||
|
||||
/* TODO: better buffer management in case there are
|
||||
* a lot of file names to escape. */
|
||||
|
||||
/* perform percent-encoding for the anchor */
|
||||
encname = qse_perenchttpstrdup (0, dirent->name, qse_httpd_getmmgr(httpd));
|
||||
if (encname == QSE_NULL)
|
||||
{
|
||||
httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* perform html escaping for the text */
|
||||
escname = qse_httpd_escapehtml (httpd, dirent->name);
|
||||
if (escname == QSE_NULL)
|
||||
{
|
||||
if (encname != dirent->name) QSE_MMGR_FREE (qse_httpd_getmmgr(httpd), encname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
qse_localtime (&dirent->stat.mtime, &bt);
|
||||
qse_mbsxfmt (tmbuf, QSE_COUNTOF(tmbuf),
|
||||
QSE_MT("%04d-%02d-%02d %02d:%02d:%02d"),
|
||||
bt.year + QSE_BTIME_YEAR_BASE, bt.mon + 1, bt.mday,
|
||||
bt.hour, bt.min, bt.sec);
|
||||
|
||||
if (dirent->stat.isdir)
|
||||
{
|
||||
fszbuf[0] = QSE_MT('\0');
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_fmtuintmaxtombs (
|
||||
fszbuf, QSE_COUNTOF(fszbuf),
|
||||
dirent->stat.size, 10, -1, QSE_MT('\0'), QSE_NULL
|
||||
);
|
||||
}
|
||||
|
||||
x = qse_mbsxfmts (
|
||||
buf, bufsz,
|
||||
QSE_MT("<tr><td class='name'><a href='%s%s' class='%s'>%s%s</a></td><td class='time'>%s</td><td class='size'>%s</td></tr>\n"),
|
||||
encname,
|
||||
(dirent->stat.isdir? QSE_MT("/"): QSE_MT("")),
|
||||
(dirent->stat.isdir? QSE_MT("dir"): QSE_MT("file")),
|
||||
escname,
|
||||
(dirent->stat.isdir? QSE_MT("/"): QSE_MT("")),
|
||||
tmbuf, fszbuf
|
||||
);
|
||||
|
||||
if (escname != dirent->name) qse_httpd_freemem (httpd, escname);
|
||||
if (encname != dirent->name) QSE_MMGR_FREE (qse_httpd_getmmgr(httpd), encname);
|
||||
|
||||
if (x == (qse_size_t)-1) httpd->errnum = QSE_HTTPD_ENOBUF;
|
||||
return x;
|
||||
}
|
||||
|
||||
static int add_footer (qse_httpd_t* httpd, qse_httpd_client_t* client, task_dseg_t* ctx)
|
||||
{
|
||||
qse_size_t x;
|
||||
int rem;
|
||||
|
||||
rem = ctx->chunked? (ctx->bufrem - 5): ctx->bufrem;
|
||||
if (rem < 1)
|
||||
{
|
||||
httpd->errnum = QSE_HTTPD_ENOBUF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
x = qse_mbsxfmts (&ctx->buf[ctx->buflen], rem, QSE_MT("</table></div>\n<div class='footer'>%s</div>\n</body></html>"), ctx->foot.ptr);
|
||||
if (x == (qse_size_t)-1)
|
||||
{
|
||||
httpd->errnum = QSE_HTTPD_ENOBUF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
QSE_ASSERT (x < rem);
|
||||
|
||||
ctx->buflen += x;
|
||||
ctx->bufrem -= x;
|
||||
|
||||
if (ctx->chunked)
|
||||
{
|
||||
qse_mbscpy (&ctx->buf[ctx->buflen], QSE_MT("\r\n0\r\n"));
|
||||
ctx->buflen += 5;
|
||||
ctx->bufrem -= 5;
|
||||
|
||||
/* -5 for \r\n0\r\n added above */
|
||||
if (ctx->chunked) close_chunk_data (ctx, ctx->buflen - 5);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int task_main_dseg (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_dseg_t* ctx = (task_dseg_t*)task->ctx;
|
||||
qse_ssize_t n;
|
||||
qse_size_t x;
|
||||
|
||||
if (ctx->bufpos < ctx->buflen)
|
||||
{
|
||||
/* buffer contents not fully sent yet */
|
||||
goto send_dirlist;
|
||||
}
|
||||
|
||||
/* the buffer size is fixed to QSE_COUNTOF(ctx->buf).
|
||||
*
|
||||
* the number of digits need to hold the the size converted to
|
||||
* a hexadecimal notation is roughly (log16(QSE_COUNTOF(ctx->buf) + 1).
|
||||
* it should be safter to use ceil(log16(QSE_COUNTOF(ctx->buf)) + 1
|
||||
* for precision issues.
|
||||
*
|
||||
* 16**X = QSE_COUNTOF(ctx->buf).
|
||||
* X = log16(QSE_COUNTOF(ctx->buf).
|
||||
* X + 1 is a required number of digits.
|
||||
*
|
||||
* Since log16 is not provided, we should use a natural log function
|
||||
* whose base is the constant e (2.718).
|
||||
*
|
||||
* log16(n) = log(n) / log(16)
|
||||
*
|
||||
* The final fomula is here.
|
||||
*
|
||||
* X = ceil((log(QSE_COUNTOF(ctx->buf)) / log(16))) + 1;
|
||||
*
|
||||
* However, i won't use these floating-point opertions.
|
||||
* instead i'll reserve a hardcoded size. so when you change
|
||||
* the size of the buffer arrray, you should check this size.
|
||||
*/
|
||||
|
||||
/* initialize buffer */
|
||||
ctx->dcount = 0; /* reset the entry counter */
|
||||
ctx->bufpos = 0;
|
||||
if (ctx->chunked)
|
||||
{
|
||||
/* reserve space to fill with the chunk length
|
||||
* 4 for the actual chunk length and +2 for \r\n */
|
||||
ctx->buflen = SIZE_CHLEN + SIZE_CHLENCRLF;
|
||||
/* free space remaing in the buffer for the chunk data */
|
||||
ctx->bufrem = QSE_COUNTOF(ctx->buf) - ctx->buflen - SIZE_CHENDCRLF;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->buflen = 0;
|
||||
ctx->bufrem = QSE_COUNTOF(ctx->buf);
|
||||
}
|
||||
|
||||
if (ctx->state & FOOTER_PENDING)
|
||||
{
|
||||
/* only footers yet to be sent */
|
||||
if (add_footer (httpd, client, ctx) <= -1)
|
||||
{
|
||||
/* return an error if the buffer is too small to hold the
|
||||
* trailing footer. you need to increase the buffer size */
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->state &= ~FOOTER_PENDING;
|
||||
ctx->state |= FOOTER_ADDED;
|
||||
|
||||
if (ctx->chunked) fill_chunk_length (ctx);
|
||||
goto send_dirlist;
|
||||
}
|
||||
|
||||
if (!(ctx->state & HEADER_ADDED))
|
||||
{
|
||||
/* compose the header since this is the first time. */
|
||||
int is_root;
|
||||
qse_mchar_t* qpath_esc;
|
||||
|
||||
is_root = (qse_mbscmp (ctx->qpath.ptr, QSE_MT("/")) == 0);
|
||||
|
||||
qpath_esc = qse_httpd_escapehtml (httpd, ctx->qpath.ptr);
|
||||
if (qpath_esc == QSE_NULL) return -1;
|
||||
|
||||
/* TODO: page encoding?? utf-8??? or derive name from cmgr or current locale??? */
|
||||
/* TODO: SUPPORT character set. DON't HARD_CODE it to UTF8 */
|
||||
x = qse_mbsxfmts (&ctx->buf[ctx->buflen], ctx->bufrem,
|
||||
QSE_MT("<html><meta http-equiv=\"Content-Type\" content=\"text/html; charset='UTF-8'\">\n<head>%s</head>\n<body>\n<div class='header'>%s</div>\n<div class='body'><table>%s"),
|
||||
ctx->head.ptr, qpath_esc,
|
||||
(is_root? QSE_MT(""): QSE_MT("<tr><td class='name'><a href='../' class='dir'>..</a></td><td class='time'></td><td class='size'></td></tr>\n"))
|
||||
);
|
||||
|
||||
if (qpath_esc != ctx->qpath.ptr) qse_httpd_freemem (httpd, qpath_esc);
|
||||
|
||||
if (x == (qse_size_t)-1)
|
||||
{
|
||||
/* return an error if the buffer is too small to
|
||||
* hold the header(httpd->errnum == QSE_HTTPD_ENOBUF).
|
||||
* i need to increase the buffer size. or i have make
|
||||
* the buffer dynamic. */
|
||||
httpd->errnum = QSE_HTTPD_ENOBUF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
QSE_ASSERT (x < ctx->bufrem);
|
||||
|
||||
ctx->buflen += x;
|
||||
ctx->bufrem -= x;
|
||||
|
||||
ctx->state |= HEADER_ADDED;
|
||||
ctx->dcount++;
|
||||
}
|
||||
|
||||
if (ctx->state & DIRENT_PENDING)
|
||||
{
|
||||
ctx->state &= ~DIRENT_PENDING;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (httpd->opt.scb.dir.read (httpd, ctx->handle, &ctx->dent) <= 0)
|
||||
ctx->state |= DIRENT_NOMORE;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (ctx->state & DIRENT_NOMORE)
|
||||
{
|
||||
/* no more directory entry */
|
||||
|
||||
if (add_footer (httpd, client, ctx) <= -1)
|
||||
{
|
||||
/* failed to add the footer part */
|
||||
if (ctx->chunked)
|
||||
{
|
||||
close_chunk_data (ctx, ctx->buflen);
|
||||
fill_chunk_length (ctx);
|
||||
}
|
||||
ctx->state |= FOOTER_PENDING;
|
||||
}
|
||||
else if (ctx->chunked) fill_chunk_length (ctx);
|
||||
break;
|
||||
}
|
||||
|
||||
if (qse_mbscmp (ctx->dent.name, QSE_MT(".")) != 0 &&
|
||||
qse_mbscmp (ctx->dent.name, QSE_MT("..")) != 0)
|
||||
{
|
||||
x = format_dirent (httpd, client, &ctx->dent, &ctx->buf[ctx->buflen], ctx->bufrem);
|
||||
if (x == (qse_size_t)-1)
|
||||
{
|
||||
/* buffer not large enough to hold this entry */
|
||||
if (ctx->dcount <= 0)
|
||||
{
|
||||
/* neither directory entry nor the header
|
||||
* has been added to the buffer so far. and
|
||||
* this attempt has failed. the buffer size must
|
||||
* be too small. you must increase it */
|
||||
httpd->errnum = QSE_HTTPD_EINTERN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->chunked)
|
||||
{
|
||||
close_chunk_data (ctx, ctx->buflen);
|
||||
fill_chunk_length (ctx);
|
||||
}
|
||||
|
||||
ctx->state |= DIRENT_PENDING;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
QSE_ASSERT (x < ctx->bufrem);
|
||||
|
||||
ctx->buflen += x;
|
||||
ctx->bufrem -= x;
|
||||
ctx->dcount++;
|
||||
ctx->tcount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (httpd->opt.scb.dir.read (httpd, ctx->handle, &ctx->dent) <= 0)
|
||||
ctx->state |= DIRENT_NOMORE;
|
||||
}
|
||||
while (1);
|
||||
|
||||
|
||||
send_dirlist:
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->opt.scb.client.send (
|
||||
httpd, client, &ctx->buf[ctx->bufpos], ctx->buflen - ctx->bufpos);
|
||||
if (n <= -1) return -1;
|
||||
|
||||
/* NOTE if (n == 0), it will enter an infinite loop */
|
||||
|
||||
ctx->bufpos += n;
|
||||
return (ctx->bufpos < ctx->buflen || (ctx->state & FOOTER_PENDING) || !(ctx->state & DIRENT_NOMORE))? 1: 0;
|
||||
}
|
||||
|
||||
static qse_httpd_task_t* entask_directory_segment (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred, qse_httpd_hnd_t handle, task_dir_t* dir)
|
||||
{
|
||||
qse_httpd_task_t task;
|
||||
task_dseg_t data;
|
||||
|
||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||
data.handle = handle;
|
||||
data.version = dir->version;
|
||||
data.keepalive = dir->keepalive;
|
||||
data.chunked = dir->keepalive;
|
||||
data.path = dir->path;
|
||||
data.qpath = dir->qpath;
|
||||
data.head = dir->head;
|
||||
data.foot = dir->foot;
|
||||
|
||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||
task.init = task_init_dseg;
|
||||
task.main = task_main_dseg;
|
||||
task.fini = task_fini_dseg;
|
||||
task.ctx = &data;
|
||||
|
||||
return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data) + data.path.len + 1 + data.qpath.len + 1 + data.head.len + 1 + data.foot.len + 1);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
static int task_init_getdir (
|
||||
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, 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);
|
||||
|
||||
xtn->head.ptr = xtn->qpath.ptr + xtn->qpath.len + 1;
|
||||
qse_mbscpy ((qse_mchar_t*)xtn->head.ptr, arg->head.ptr);
|
||||
xtn->foot.ptr = xtn->head.ptr + xtn->head.len + 1;
|
||||
qse_mbscpy ((qse_mchar_t*)xtn->foot.ptr, arg->foot.ptr);
|
||||
|
||||
/* switch the context to the extension area */
|
||||
task->ctx = xtn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static QSE_INLINE int task_main_getdir (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_dir_t* dir;
|
||||
qse_httpd_task_t* x;
|
||||
|
||||
dir = (task_dir_t*)task->ctx;
|
||||
x = task;
|
||||
|
||||
/* arrange to return the header part first */
|
||||
if (dir->method == QSE_HTTP_HEAD)
|
||||
{
|
||||
x = qse_httpd_entaskformat (
|
||||
httpd, client, x,
|
||||
QSE_MT("HTTP/%d.%d 200 OK\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: text/html\r\nContent-Length: 0\r\n\r\n"),
|
||||
dir->version.major, dir->version.minor,
|
||||
qse_httpd_getname (httpd),
|
||||
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
|
||||
(dir->keepalive? QSE_MT("keep-alive"): QSE_MT("close"))
|
||||
);
|
||||
|
||||
httpd->opt.scb.dir.close (httpd, dir->handle);
|
||||
return (x == QSE_NULL)? -1: 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int keepalive_ignored = 0;
|
||||
|
||||
if (dir->keepalive && qse_comparehttpversions (&dir->version, &qse_http_v11) < 0)
|
||||
{
|
||||
/* this task does chunking when keepalive is set.
|
||||
* chunking is not supported for http 1.0 or earlier.
|
||||
* force switch to the close mode */
|
||||
dir->keepalive = 0;
|
||||
keepalive_ignored = 1;
|
||||
}
|
||||
|
||||
x = qse_httpd_entaskformat (
|
||||
httpd, client, x,
|
||||
QSE_MT("HTTP/%d.%d 200 OK\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: text/html\r\n%s\r\n"),
|
||||
dir->version.major, dir->version.minor,
|
||||
qse_httpd_getname (httpd),
|
||||
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
|
||||
(dir->keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
|
||||
(dir->keepalive? QSE_MT("Transfer-Encoding: chunked\r\n"): QSE_MT(""))
|
||||
);
|
||||
if (x)
|
||||
{
|
||||
#if 0
|
||||
if (httpd->opt.trait & QSE_HTTPD_LOGACC)
|
||||
{
|
||||
qse_httpd_reqsum_t reqsum;
|
||||
|
||||
acc.remote = remote;
|
||||
acc.qpath = qpath;
|
||||
acc.status = 200;
|
||||
acc.version = ...;
|
||||
acc.method = ...;
|
||||
|
||||
httpd->opt.rcb.logacc (httpd, &reqsum);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* arrange to send the actual directory contents */
|
||||
x = entask_directory_segment (httpd, client, x, dir->handle, dir);
|
||||
if (keepalive_ignored && x)
|
||||
x = qse_httpd_entaskdisconnect (httpd, client, x);
|
||||
if (x) return 0;
|
||||
|
||||
}
|
||||
|
||||
httpd->opt.scb.dir.close (httpd, dir->handle);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entaskdir (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred,
|
||||
qse_httpd_rsrc_dir_t* dir,
|
||||
qse_htre_t* req)
|
||||
{
|
||||
int method;
|
||||
|
||||
method = qse_htre_getqmethodtype(req);
|
||||
|
||||
/* i don't need contents for directories */
|
||||
qse_htre_discardcontent (req);
|
||||
|
||||
switch (method)
|
||||
{
|
||||
case QSE_HTTP_OPTIONS:
|
||||
return qse_httpd_entaskallow (httpd, client, pred,
|
||||
QSE_MT("OPTIONS,GET,HEAD,POST,PUT,DELETE"), req);
|
||||
|
||||
case QSE_HTTP_HEAD:
|
||||
case QSE_HTTP_GET:
|
||||
case QSE_HTTP_POST:
|
||||
{
|
||||
task_dir_t data;
|
||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||
|
||||
/* check if the directory stream can be opened before
|
||||
* creating an actual task. */
|
||||
if (httpd->opt.scb.dir.open (httpd, dir->path, &data.handle) <= -1)
|
||||
{
|
||||
/* arrange a status code to return */
|
||||
int status;
|
||||
status = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
|
||||
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
||||
return qse_httpd_entaskerror (httpd, client, pred, status, req);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* create a directory listing task */
|
||||
qse_httpd_task_t task, * x;
|
||||
|
||||
data.path.ptr = (qse_mchar_t*)dir->path;
|
||||
data.path.len = qse_mbslen(data.path.ptr);
|
||||
data.qpath.ptr = qse_htre_getqpath(req);
|
||||
data.qpath.len = qse_mbslen(data.qpath.ptr);
|
||||
data.head.ptr = dir->head? (qse_mchar_t*)dir->head: QSE_MT("<style type='text/css'>body { background-color:#d0e4fe; font-size: 0.9em; } div.header { font-weight: bold; margin-bottom: 5px; } div.footer { border-top: 1px solid #99AABB; text-align: right; } table { font-size: 0.9em; } td { white-space: nowrap; } td.size { text-align: right; }</style>");
|
||||
data.head.len = qse_mbslen(data.head.ptr);
|
||||
data.foot.ptr = dir->foot? dir->foot: qse_httpd_getname(httpd);
|
||||
data.foot.len = qse_mbslen(data.foot.ptr);
|
||||
data.version = *qse_htre_getversion(req);
|
||||
data.keepalive = req->flags & QSE_HTRE_ATTR_KEEPALIVE;
|
||||
data.method = method;
|
||||
|
||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||
task.init = task_init_getdir;
|
||||
task.main = task_main_getdir;
|
||||
task.ctx = &data;
|
||||
|
||||
x = qse_httpd_entask (httpd, client, pred, &task,
|
||||
QSE_SIZEOF(task_dir_t) + data.path.len + 1 + data.qpath.len + 1 +
|
||||
data.head.len + 1 + data.foot.len + 1);
|
||||
if (x == QSE_NULL)
|
||||
{
|
||||
httpd->opt.scb.dir.close (httpd, data.handle);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
case QSE_HTTP_PUT:
|
||||
{
|
||||
int status = 201; /* 201 Created */
|
||||
|
||||
if (httpd->opt.scb.dir.make (httpd, dir->path) <= -1)
|
||||
{
|
||||
if (httpd->errnum == QSE_HTTPD_EEXIST)
|
||||
{
|
||||
/* an entry with the same name exists.
|
||||
* if it is a directory, it's considered ok.
|
||||
* if not, send '403 forbidden' indicating you can't
|
||||
* change a file to a directory */
|
||||
qse_httpd_stat_t st;
|
||||
status = (httpd->opt.scb.dir.stat (httpd, dir->path, &st) <= -1)? 403: 204;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
|
||||
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
||||
}
|
||||
}
|
||||
|
||||
return qse_httpd_entaskerror (httpd, client, pred, status, req);
|
||||
}
|
||||
|
||||
|
||||
case QSE_HTTP_DELETE:
|
||||
{
|
||||
int status = 200;
|
||||
|
||||
if (httpd->opt.scb.dir.purge (httpd, dir->path) <= -1)
|
||||
{
|
||||
status = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
|
||||
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
||||
}
|
||||
|
||||
return qse_httpd_entaskerror (httpd, client, pred, status, req);
|
||||
}
|
||||
|
||||
default:
|
||||
/* Method not allowed */
|
||||
return qse_httpd_entaskerror (httpd, client, pred, 405, req);
|
||||
}
|
||||
}
|
656
lib/http/httpd-file.c
Normal file
656
lib/http/httpd-file.c
Normal file
@ -0,0 +1,656 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "httpd.h"
|
||||
#include "../cmn/mem-prv.h"
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/fmt.h>
|
||||
|
||||
#define ETAG_LEN_MAX 127
|
||||
|
||||
#define PUTFILE_INIT_FAILED (1 << 0)
|
||||
#define PUTFILE_WRITE_FAILED (1 << 1)
|
||||
|
||||
typedef struct task_file_t task_file_t;
|
||||
struct task_file_t
|
||||
{
|
||||
qse_mcstr_t path;
|
||||
|
||||
qse_http_version_t version;
|
||||
int keepalive;
|
||||
int method;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
qse_mcstr_t mime;
|
||||
qse_mchar_t if_none_match[ETAG_LEN_MAX + 1];
|
||||
qse_ntime_t if_modified_since;
|
||||
qse_http_range_t range;
|
||||
} get;
|
||||
struct
|
||||
{
|
||||
qse_httpd_t* httpd;
|
||||
int flags;
|
||||
int status;
|
||||
qse_htre_t* req;
|
||||
qse_httpd_hnd_t handle;
|
||||
} put;
|
||||
} u;
|
||||
};
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
typedef struct task_getfseg_t task_getfseg_t;
|
||||
struct task_getfseg_t
|
||||
{
|
||||
qse_httpd_hnd_t handle;
|
||||
qse_foff_t left;
|
||||
qse_foff_t offset;
|
||||
};
|
||||
|
||||
static int task_init_getfseg (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_getfseg_t* xtn = qse_httpd_gettaskxtn (httpd, task);
|
||||
QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn));
|
||||
task->ctx = xtn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void task_fini_getfseg (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_getfseg_t* ctx = (task_getfseg_t*)task->ctx;
|
||||
httpd->opt.scb.file.close (httpd, ctx->handle);
|
||||
}
|
||||
|
||||
static int task_main_getfseg (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
qse_ssize_t n;
|
||||
qse_size_t count;
|
||||
task_getfseg_t* ctx = (task_getfseg_t*)task->ctx;
|
||||
|
||||
count = MAX_SEND_SIZE;
|
||||
if (count >= ctx->left) count = ctx->left;
|
||||
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->opt.scb.client.sendfile (
|
||||
httpd, client, ctx->handle, &ctx->offset, count);
|
||||
if (n <= -1)
|
||||
{
|
||||
/* HANDLE EGAIN specially??? */
|
||||
if (httpd->errnum != QSE_HTTPD_EAGAIN)
|
||||
{
|
||||
/* TODO: logging */
|
||||
return -1;
|
||||
}
|
||||
|
||||
goto more_work;
|
||||
}
|
||||
|
||||
if (n == 0 && count > 0)
|
||||
{
|
||||
/* The file could be truncated when this condition is set.
|
||||
* The content-length sent in the header can't be fulfilled.
|
||||
* So let's return an error here so that the main loop abort
|
||||
* the connection. */
|
||||
/* TODO: any logging....??? */
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->left -= n;
|
||||
if (ctx->left <= 0) return 0;
|
||||
|
||||
more_work:
|
||||
return 1; /* more work to do */
|
||||
}
|
||||
|
||||
static qse_httpd_task_t* entask_getfseg (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred,
|
||||
qse_httpd_hnd_t handle, qse_foff_t offset, qse_foff_t size)
|
||||
{
|
||||
qse_httpd_task_t task;
|
||||
task_getfseg_t data;
|
||||
|
||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||
data.handle = handle;
|
||||
data.offset = offset;
|
||||
data.left = size;
|
||||
|
||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||
task.init = task_init_getfseg;
|
||||
task.main = task_main_getfseg;
|
||||
task.fini = task_fini_getfseg;
|
||||
task.ctx = &data;
|
||||
|
||||
return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data));
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
static int task_init_getfile (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
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->u.get.mime.ptr)
|
||||
{
|
||||
file->u.get.mime.ptr = file->path.ptr + file->path.len + 1;
|
||||
qse_mbscpy ((qse_mchar_t*)file->u.get.mime.ptr, arg->u.get.mime.ptr);
|
||||
}
|
||||
|
||||
task->ctx = file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static QSE_INLINE int task_main_getfile (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_file_t* file;
|
||||
qse_httpd_task_t* x;
|
||||
qse_httpd_hnd_t handle;
|
||||
int fileopen = 0;
|
||||
qse_httpd_stat_t st;
|
||||
|
||||
file = (task_file_t*)task->ctx;
|
||||
x = task;
|
||||
|
||||
/* TODO: if you should deal with files on a network-mounted drive,
|
||||
setting a trigger or non-blocking I/O are needed. */
|
||||
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
if (httpd->opt.scb.file.stat (httpd, file->path.ptr, &st) <= -1)
|
||||
{
|
||||
int http_errnum;
|
||||
http_errnum = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
|
||||
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
||||
x = qse_httpd_entaskerrorwithmvk (
|
||||
httpd, client, x, http_errnum,
|
||||
file->method, &file->version, file->keepalive);
|
||||
goto no_file_send;
|
||||
}
|
||||
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
if (httpd->opt.scb.file.ropen (httpd, file->path.ptr, &handle) <= -1)
|
||||
{
|
||||
int http_errnum;
|
||||
http_errnum = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
|
||||
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
||||
x = qse_httpd_entaskerrorwithmvk (
|
||||
httpd, client, x, http_errnum,
|
||||
file->method, &file->version, file->keepalive);
|
||||
goto no_file_send;
|
||||
}
|
||||
fileopen = 1;
|
||||
|
||||
if (file->u.get.range.type != QSE_HTTP_RANGE_NONE)
|
||||
{
|
||||
qse_mchar_t tmp[4][64];
|
||||
qse_mchar_t etag[ETAG_LEN_MAX + 1];
|
||||
qse_size_t etag_len;
|
||||
|
||||
if (file->u.get.range.type == QSE_HTTP_RANGE_SUFFIX)
|
||||
{
|
||||
if (file->u.get.range.to > st.size) file->u.get.range.to = st.size;
|
||||
file->u.get.range.from = st.size - file->u.get.range.to;
|
||||
file->u.get.range.to = file->u.get.range.to + file->u.get.range.from;
|
||||
if (st.size > 0) file->u.get.range.to--;
|
||||
}
|
||||
|
||||
if (file->u.get.range.from >= st.size)
|
||||
{
|
||||
x = qse_httpd_entaskerrorwithmvk (
|
||||
httpd, client, x, 416, file->method, &file->version, file->keepalive);
|
||||
goto no_file_send;
|
||||
}
|
||||
|
||||
if (file->u.get.range.to >= st.size) file->u.get.range.to = st.size - 1;
|
||||
|
||||
qse_fmtuintmaxtombs (tmp[0], QSE_COUNTOF(tmp[0]), (file->u.get.range.to - file->u.get.range.from + 1), 10, -1, QSE_MT('\0'), QSE_NULL);
|
||||
qse_fmtuintmaxtombs (tmp[1], QSE_COUNTOF(tmp[1]), file->u.get.range.from, 10, -1, QSE_MT('\0'), QSE_NULL);
|
||||
qse_fmtuintmaxtombs (tmp[2], QSE_COUNTOF(tmp[2]), file->u.get.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), st.mtime.sec, 16, -1, QSE_MT('\0'), QSE_NULL);
|
||||
etag[etag_len++] = QSE_MT('-');
|
||||
etag_len += qse_fmtuintmaxtombs (&etag[etag_len], QSE_COUNTOF(etag), st.mtime.nsec, 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('-');
|
||||
etag_len += qse_fmtuintmaxtombs (&etag[etag_len], QSE_COUNTOF(etag) - etag_len, st.ino, 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.dev, 16, -1, QSE_MT('\0'), QSE_NULL);
|
||||
|
||||
x = qse_httpd_entaskformat (
|
||||
httpd, client, x,
|
||||
QSE_MT("HTTP/%d.%d 206 Partial Content\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\n%s%s%sContent-Length: %s\r\nContent-Range: bytes %s-%s/%s\r\nAccept-Ranges: bytes\r\nLast-Modified: %s\r\nETag: %s\r\n\r\n"),
|
||||
file->version.major, file->version.minor,
|
||||
qse_httpd_getname (httpd),
|
||||
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
|
||||
(file->keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
|
||||
(file->u.get.mime.len > 0? QSE_MT("Content-Type: "): QSE_MT("")),
|
||||
(file->u.get.mime.len > 0? file->u.get.mime.ptr: QSE_MT("")),
|
||||
(file->u.get.mime.len > 0? QSE_MT("\r\n"): QSE_MT("")),
|
||||
((file->method == QSE_HTTP_HEAD)? QSE_MT("0"): tmp[0]),
|
||||
tmp[1], tmp[2], tmp[3],
|
||||
qse_httpd_fmtgmtimetobb (httpd, &st.mtime, 1),
|
||||
etag
|
||||
);
|
||||
if (x)
|
||||
{
|
||||
if (file->method == QSE_HTTP_HEAD) goto no_file_send;
|
||||
x = entask_getfseg (
|
||||
httpd, client, x, handle,
|
||||
file->u.get.range.from,
|
||||
(file->u.get.range.to - file->u.get.range.from + 1)
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_mchar_t b_fsize[64];
|
||||
qse_mchar_t etag[ETAG_LEN_MAX + 1];
|
||||
qse_size_t etag_len;
|
||||
|
||||
etag_len = qse_fmtuintmaxtombs (&etag[0], QSE_COUNTOF(etag), st.mtime.sec, 16, -1, QSE_MT('\0'), QSE_NULL);
|
||||
etag[etag_len++] = QSE_MT('-');
|
||||
etag_len += qse_fmtuintmaxtombs (&etag[etag_len], QSE_COUNTOF(etag), st.mtime.nsec, 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('-');
|
||||
etag_len += qse_fmtuintmaxtombs (&etag[etag_len], QSE_COUNTOF(etag) - etag_len, st.ino, 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.dev, 16, -1, QSE_MT('\0'), QSE_NULL);
|
||||
|
||||
if ((file->u.get.if_none_match[0] != QSE_MT('\0') && qse_mbscmp (etag, file->u.get.if_none_match) == 0) ||
|
||||
(file->u.get.if_modified_since.sec > 0 && st.mtime.sec <= file->u.get.if_modified_since.sec))
|
||||
{
|
||||
/* i've converted milliseconds to seconds before timestamp comparison
|
||||
* because st.mtime has the actual milliseconds less than 1 second
|
||||
* while if_modified_since doesn't have such small milliseconds */
|
||||
x = qse_httpd_entask_nomod (httpd, client, x, file->method, &file->version, file->keepalive);
|
||||
goto no_file_send;
|
||||
}
|
||||
|
||||
qse_fmtuintmaxtombs (b_fsize, QSE_COUNTOF(b_fsize), st.size, 10, -1, QSE_MT('\0'), QSE_NULL);
|
||||
|
||||
/* wget 1.8.2 set 'Connection: keep-alive' in the http 1.0 header.
|
||||
* if the reply doesn't contain 'Connection: keep-alive', it didn't
|
||||
* close connection.*/
|
||||
|
||||
x = qse_httpd_entaskformat (
|
||||
httpd, client, x,
|
||||
QSE_MT("HTTP/%d.%d 200 OK\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\n%s%s%sContent-Length: %s\r\nAccept-Ranges: bytes\r\nLast-Modified: %s\r\nETag: %s\r\n\r\n"),
|
||||
file->version.major, file->version.minor,
|
||||
qse_httpd_getname (httpd),
|
||||
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
|
||||
(file->keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
|
||||
(file->u.get.mime.len > 0? QSE_MT("Content-Type: "): QSE_MT("")),
|
||||
(file->u.get.mime.len > 0? file->u.get.mime.ptr: QSE_MT("")),
|
||||
(file->u.get.mime.len > 0? QSE_MT("\r\n"): QSE_MT("")),
|
||||
((file->method == QSE_HTTP_HEAD)? QSE_MT("0"): b_fsize),
|
||||
qse_httpd_fmtgmtimetobb (httpd, &st.mtime, 1),
|
||||
etag
|
||||
);
|
||||
if (x)
|
||||
{
|
||||
if (file->method == QSE_HTTP_HEAD) goto no_file_send;
|
||||
x = entask_getfseg (httpd, client, x, handle, 0, st.size);
|
||||
}
|
||||
}
|
||||
|
||||
if (x) return 0;
|
||||
httpd->opt.scb.file.close (httpd, handle);
|
||||
return -1;
|
||||
|
||||
no_file_send:
|
||||
if (fileopen) httpd->opt.scb.file.close (httpd, handle);
|
||||
return (x == QSE_NULL)? -1: 0;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
static int write_file (qse_httpd_t* httpd, qse_httpd_hnd_t handle, const qse_mchar_t* ptr, qse_size_t len)
|
||||
{
|
||||
qse_ssize_t n;
|
||||
qse_size_t pos = 0;
|
||||
|
||||
/* this implementation assumes that file writing will never get
|
||||
* blocked in practice. so no i/o multiplexing is performed over
|
||||
* file descriptors */
|
||||
while (pos < len)
|
||||
{
|
||||
n = httpd->opt.scb.file.write (httpd, handle, &ptr[pos], len - pos);
|
||||
if (n <= 0) return -1;
|
||||
pos += n;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int putfile_snatch_client_input (
|
||||
qse_htre_t* req, const qse_mchar_t* ptr, qse_size_t len, void* ctx)
|
||||
{
|
||||
qse_httpd_task_t* task;
|
||||
task_file_t* file;
|
||||
|
||||
task = (qse_httpd_task_t*)ctx;
|
||||
file = (task_file_t*)task->ctx;
|
||||
|
||||
if (ptr == QSE_NULL)
|
||||
{
|
||||
/*
|
||||
* this callback is called with ptr of QSE_NULL
|
||||
* when the request is completed or discarded.
|
||||
* and this indicates that there's nothing more to read
|
||||
* from the client side. this can happen when the end of
|
||||
* a request is seen or when an error occurs
|
||||
*/
|
||||
QSE_ASSERT (len == 0);
|
||||
|
||||
/* mark the there's nothing to read form the client side */
|
||||
qse_htre_unsetconcb (file->u.put.req);
|
||||
file->u.put.req = QSE_NULL;
|
||||
|
||||
/* since there is no more to read from the client side.
|
||||
* the trigger is not needed any more. */
|
||||
task->trigger.v[0].mask = 0;
|
||||
}
|
||||
else if (!(file->u.put.flags & PUTFILE_WRITE_FAILED))
|
||||
{
|
||||
if (write_file (file->u.put.httpd, file->u.put.handle, ptr, len) <= -1)
|
||||
{
|
||||
file->u.put.flags |= PUTFILE_WRITE_FAILED;
|
||||
file->u.put.status = 500;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int task_init_putfile (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_file_t* file = qse_httpd_gettaskxtn (httpd, task);
|
||||
task_file_t* arg = (task_file_t*)task->ctx;
|
||||
qse_httpd_stat_t st;
|
||||
|
||||
/* zero out the task's extension area */
|
||||
QSE_MEMCPY (file, arg, QSE_SIZEOF(*file));
|
||||
file->u.put.req = QSE_NULL;
|
||||
|
||||
/* copy in the path name to the area */
|
||||
file->path.ptr = (qse_mchar_t*)(file + 1);
|
||||
qse_mbscpy ((qse_mchar_t*)file->path.ptr, arg->path.ptr);
|
||||
file->u.put.status = 204; /* 200 should also be ok to indicate success. */
|
||||
task->ctx = file; /* switch the task context to the extension area */
|
||||
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
if (httpd->opt.scb.file.stat (httpd, file->path.ptr, &st) <= -1)
|
||||
{
|
||||
if (httpd->errnum == QSE_HTTPD_ENOENT)
|
||||
{
|
||||
/* stat found no such file. so if the request is achived
|
||||
* successfully, it should send '201 Created' */
|
||||
file->u.put.status = 201;
|
||||
}
|
||||
}
|
||||
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
if (httpd->opt.scb.file.wopen (httpd, file->path.ptr, &file->u.put.handle) <= -1)
|
||||
{
|
||||
file->u.put.status = (httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (write_file (httpd, file->u.put.handle, qse_htre_getcontentptr(arg->u.put.req), qse_htre_getcontentlen(arg->u.put.req)) <= -1)
|
||||
{
|
||||
httpd->opt.scb.file.close (httpd, file->u.put.handle);
|
||||
file->u.put.status = 500;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (!(arg->u.put.req->state & QSE_HTRE_DISCARDED) &&
|
||||
!(arg->u.put.req->state & QSE_HTRE_COMPLETED))
|
||||
{
|
||||
/* set up a callback to be called when the request content
|
||||
* is fed to the htrd reader. qse_htre_addcontent() that
|
||||
* htrd calls invokes this callback. */
|
||||
file->u.put.req = arg->u.put.req;
|
||||
qse_htre_setconcb (file->u.put.req, putfile_snatch_client_input, task);
|
||||
}
|
||||
|
||||
/* no triggers yet since the main loop doesn't allow me to set
|
||||
* triggers in the task initializer. however the main task handler
|
||||
* will be invoked so long as the client handle is writable by
|
||||
* the main loop. */
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
/* since a new task can't be added in the initializer,
|
||||
* i mark that initialization failed and let task_main_putfile()
|
||||
* add an error task */
|
||||
qse_htre_discardcontent (arg->u.put.req);
|
||||
file->u.put.flags |= PUTFILE_INIT_FAILED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void task_fini_putfile (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_file_t* file = (task_file_t*)task->ctx;
|
||||
|
||||
if (!(file->u.put.flags & PUTFILE_INIT_FAILED))
|
||||
httpd->opt.scb.file.close (httpd, file->u.put.handle);
|
||||
}
|
||||
|
||||
static int task_main_putfile_2 (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_file_t* file = (task_file_t*)task->ctx;
|
||||
|
||||
if (file->u.put.req)
|
||||
{
|
||||
/* file->u.put.req is set to a non-NULL value if snatching
|
||||
* is needed in the task_init_putfile(). and it's reset to
|
||||
* QSE_NULL when snatching is over in putfile_snatch_client_input().
|
||||
* i set a trigger so that the task is executed
|
||||
* while there is input from the client side */
|
||||
/*task->trigger.v[0].mask = QSE_HTTPD_TASK_TRIGGER_READ;
|
||||
task->trigger.v[0].handle = client->handle;*/
|
||||
task->trigger.cmask = QSE_HTTPD_TASK_TRIGGER_READ;
|
||||
return 1; /* trigger me when a client sends data */
|
||||
}
|
||||
|
||||
/* snatching is over. writing error may have occurred as well.
|
||||
* file->u.put.status should hold a proper status code */
|
||||
if (qse_httpd_entaskerrorwithmvk (
|
||||
httpd, client, task, file->u.put.status,
|
||||
file->method, &file->version, file->keepalive) == QSE_NULL) return -1;
|
||||
return 0; /* no more data to read. task over */
|
||||
}
|
||||
|
||||
static int task_main_putfile (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_file_t* file = (task_file_t*)task->ctx;
|
||||
|
||||
if (!(file->u.put.flags & PUTFILE_INIT_FAILED) && file->u.put.req)
|
||||
{
|
||||
/* initialization was successful and snatching is required.
|
||||
* switch to the next phase. */
|
||||
task->main = task_main_putfile_2;
|
||||
return task_main_putfile_2 (httpd, client, task);
|
||||
}
|
||||
|
||||
/* snatching is not required or initialization error has occurred.
|
||||
* file->u.put.status should hold a proper status code.
|
||||
*
|
||||
* note: if initialization error occurred and there is contents for the
|
||||
* client to send, this reply may get to the client before it finishes
|
||||
* sending the contents. */
|
||||
if (qse_httpd_entaskerrorwithmvk (
|
||||
httpd, client, task, file->u.put.status,
|
||||
file->method, &file->version, file->keepalive) == QSE_NULL) return -1;
|
||||
return 0; /* task over */
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entaskfile (
|
||||
qse_httpd_t* httpd,
|
||||
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;
|
||||
task_file_t data;
|
||||
const qse_htre_hdrval_t* tmp;
|
||||
qse_size_t xtnsize;
|
||||
|
||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||
data.path.ptr = (qse_mchar_t*)path;
|
||||
data.path.len = qse_mbslen(path);
|
||||
data.version = *qse_htre_getversion(req);
|
||||
data.keepalive = (req->flags & QSE_HTRE_ATTR_KEEPALIVE);
|
||||
data.method = qse_htre_getqmethodtype(req);
|
||||
|
||||
xtnsize = QSE_SIZEOF(task_file_t) + data.path.len + 1;
|
||||
|
||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||
|
||||
switch (data.method)
|
||||
{
|
||||
case QSE_HTTP_OPTIONS:
|
||||
qse_htre_discardcontent (req);
|
||||
return qse_httpd_entaskallow (httpd, client, pred,
|
||||
QSE_MT("OPTIONS,GET,HEAD,POST,PUT,DELETE"), req);
|
||||
|
||||
case QSE_HTTP_HEAD:
|
||||
case QSE_HTTP_GET:
|
||||
case QSE_HTTP_POST:
|
||||
qse_htre_discardcontent (req);
|
||||
|
||||
if (mime)
|
||||
{
|
||||
data.u.get.mime.ptr = (qse_mchar_t*)mime;
|
||||
data.u.get.mime.len = qse_mbslen(mime);
|
||||
xtnsize += data.u.get.mime.len + 1;
|
||||
}
|
||||
|
||||
tmp = qse_htre_getheaderval(req, QSE_MT("If-None-Match"));
|
||||
if (tmp)
|
||||
{
|
||||
/*while (tmp->next) tmp = tmp->next;*/ /* get the last value */
|
||||
qse_mbsxcpy (data.u.get.if_none_match, QSE_COUNTOF(data.u.get.if_none_match), tmp->ptr);
|
||||
}
|
||||
if (data.u.get.if_none_match[0] == QSE_MT('\0'))
|
||||
{
|
||||
/* Both ETag and Last-Modified are included in the reply.
|
||||
* If the client understand ETag, it can choose to include
|
||||
* If-None-Match in the request. If it understands Last-Modified,
|
||||
* it can choose to include If-Modified-Since. I don't care
|
||||
* the client understands both and include both of them
|
||||
* in the request.
|
||||
*
|
||||
* I check If-None-Match if it's included.
|
||||
* I check If-Modified-Since if If-None-Match is not included.
|
||||
*/
|
||||
tmp = qse_htre_getheaderval(req, QSE_MT("If-Modified-Since"));
|
||||
if (tmp)
|
||||
{
|
||||
/*while (tmp->next) tmp = tmp->next;*/ /* get the last value */
|
||||
if (qse_parsehttptime (tmp->ptr, &data.u.get.if_modified_since) <= -1)
|
||||
{
|
||||
data.u.get.if_modified_since.sec = 0;
|
||||
data.u.get.if_modified_since.nsec = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tmp = qse_htre_getheaderval(req, QSE_MT("Range"));
|
||||
if (tmp)
|
||||
{
|
||||
/*while (tmp->next) tmp = tmp->next;*/ /* get the last value */
|
||||
if (qse_parsehttprange (tmp->ptr, &data.u.get.range) <= -1)
|
||||
{
|
||||
return qse_httpd_entaskerror (httpd, client, pred, 416, req);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data.u.get.range.type = QSE_HTTP_RANGE_NONE;
|
||||
}
|
||||
|
||||
task.init = task_init_getfile;
|
||||
task.main = task_main_getfile;
|
||||
|
||||
task.ctx = &data;
|
||||
return qse_httpd_entask (httpd, client, pred, &task, xtnsize);
|
||||
|
||||
case QSE_HTTP_PUT:
|
||||
/* note that no partial update is supported for PUT */
|
||||
data.u.put.httpd = httpd;
|
||||
data.u.put.req = req;
|
||||
task.init = task_init_putfile;
|
||||
task.main = task_main_putfile;
|
||||
task.fini = task_fini_putfile;
|
||||
task.ctx = &data;
|
||||
return qse_httpd_entask (httpd, client, pred, &task, xtnsize);
|
||||
|
||||
case QSE_HTTP_DELETE:
|
||||
{
|
||||
int status = 200;
|
||||
|
||||
qse_htre_discardcontent (req);
|
||||
if (httpd->opt.scb.file.purge (httpd, path) <= -1)
|
||||
{
|
||||
status = (httpd->errnum == QSE_HTTPD_ENOENT)? 404:
|
||||
(httpd->errnum == QSE_HTTPD_EACCES)? 403: 500;
|
||||
}
|
||||
|
||||
return qse_httpd_entaskerror (httpd, client, pred, status, req);
|
||||
}
|
||||
|
||||
default:
|
||||
/* Method not allowed */
|
||||
qse_htre_discardcontent (req);
|
||||
return qse_httpd_entaskerror (httpd, client, pred, 405, req);
|
||||
}
|
||||
}
|
||||
|
2594
lib/http/httpd-proxy.c
Normal file
2594
lib/http/httpd-proxy.c
Normal file
File diff suppressed because it is too large
Load Diff
1064
lib/http/httpd-std-dns.h
Normal file
1064
lib/http/httpd-std-dns.h
Normal file
File diff suppressed because it is too large
Load Diff
215
lib/http/httpd-std-mod.h
Normal file
215
lib/http/httpd-std-mod.h
Normal file
@ -0,0 +1,215 @@
|
||||
/* Override the global definition QSE_ENABLE_STATIC_MODULE
|
||||
* for httpd on platforms with mature dynamic loading support.
|
||||
*/
|
||||
#if defined(QSE_ENABLE_STATIC_MODULE) && \
|
||||
(defined(USE_LTDL) || defined(_WIN32) || defined(__OS2__))
|
||||
# undef QSE_ENABLE_STATIC_MODULE
|
||||
#endif
|
||||
|
||||
static void* mod_open (qse_httpd_t* httpd, const qse_char_t* sysname)
|
||||
{
|
||||
#if defined(USE_LTDL)
|
||||
void* h;
|
||||
qse_mchar_t* modpath;
|
||||
|
||||
#if defined(QSE_CHAR_IS_MCHAR)
|
||||
modpath = sysname;
|
||||
#else
|
||||
modpath = qse_wcstombsdup (sysname, QSE_NULL, qse_httpd_getmmgr(httpd));
|
||||
if (!modpath)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM);
|
||||
return QSE_NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
h = lt_dlopenext (modpath);
|
||||
if (!h) qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||
|
||||
#if defined(QSE_CHAR_IS_MCHAR)
|
||||
/* do nothing */
|
||||
#else
|
||||
QSE_MMGR_FREE (qse_httpd_getmmgr(httpd), modpath);
|
||||
#endif
|
||||
|
||||
return h;
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
HMODULE h;
|
||||
|
||||
h = LoadLibrary (sysname);
|
||||
if (!h) qse_httpd_seterrnum (httpd, syserr_to_errnum(GetLastError()));
|
||||
|
||||
QSE_ASSERT (QSE_SIZEOF(h) <= QSE_SIZEOF(void*));
|
||||
return h;
|
||||
|
||||
#elif defined(__OS2__)
|
||||
|
||||
HMODULE h;
|
||||
qse_mchar_t* modpath;
|
||||
char errbuf[CCHMAXPATH];
|
||||
APIRET rc;
|
||||
|
||||
#if defined(QSE_CHAR_IS_MCHAR)
|
||||
modpath = sysname;
|
||||
#else
|
||||
modpath = qse_wcstombsdup (sysname, QSE_NULL, qse_httpd_getmmgr(httpd));
|
||||
if (!modpath)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM);
|
||||
return QSE_NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* DosLoadModule() seems to have severe limitation on
|
||||
* the file name it can load (max-8-letters.xxx) */
|
||||
rc = DosLoadModule (errbuf, QSE_COUNTOF(errbuf) - 1, modpath, &h);
|
||||
if (rc != NO_ERROR)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(rc));
|
||||
h = QSE_NULL;
|
||||
}
|
||||
|
||||
#if defined(QSE_CHAR_IS_MCHAR)
|
||||
/* do nothing */
|
||||
#else
|
||||
QSE_MMGR_FREE (qse_httpd_getmmgr(httpd), modpath);
|
||||
#endif
|
||||
|
||||
QSE_ASSERT (QSE_SIZEOF(h) <= QSE_SIZEOF(void*));
|
||||
return h;
|
||||
|
||||
#elif defined(__DOS__) && defined(QSE_ENABLE_DOS_DYNAMIC_MODULE)
|
||||
|
||||
/* the DOS code here is not generic enough. it's for a specific
|
||||
* dos-extender only. the best is to disable dynamic loading
|
||||
* when building for DOS. */
|
||||
void* h;
|
||||
qse_mchar_t* modpath;
|
||||
|
||||
#if defined(QSE_CHAR_IS_MCHAR)
|
||||
modpath = sysname;
|
||||
#else
|
||||
modpath = qse_wcstombsdup (sysname, QSE_NULL, qse_httpd_getmmgr(httpd));
|
||||
if (!modpath)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM);
|
||||
return QSE_NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
h = LoadModule (modpath);
|
||||
if (!h) qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||
|
||||
#if defined(QSE_CHAR_IS_MCHAR)
|
||||
/* do nothing */
|
||||
#else
|
||||
QSE_MMGR_FREE (qse_httpd_getmmgr(httpd), modpath);
|
||||
#endif
|
||||
|
||||
QSE_ASSERT (QSE_SIZEOF(h) <= QSE_SIZEOF(void*));
|
||||
return h;
|
||||
#elif defined(USE_DLFCN)
|
||||
|
||||
void* h;
|
||||
qse_mchar_t* modpath;
|
||||
|
||||
#if defined(QSE_CHAR_IS_MCHAR)
|
||||
modpath = sysname;
|
||||
#else
|
||||
modpath = qse_wcstombsdup (sysname, QSE_NULL, qse_httpd_getmmgr(httpd));
|
||||
if (!modpath)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM);
|
||||
return QSE_NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
h = dlopen(modpath, RTLD_NOW);
|
||||
if (!h) qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR);
|
||||
|
||||
#if defined(QSE_CHAR_IS_MCHAR)
|
||||
/* do nothing */
|
||||
#else
|
||||
QSE_MMGR_FREE (qse_httpd_getmmgr(httpd), modpath);
|
||||
#endif
|
||||
|
||||
return h;
|
||||
|
||||
#else
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL);
|
||||
return QSE_NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mod_close (qse_httpd_t* httpd, void* handle)
|
||||
{
|
||||
#if defined(USE_LTDL)
|
||||
lt_dlclose (handle);
|
||||
#elif defined(_WIN32)
|
||||
FreeLibrary ((HMODULE)handle);
|
||||
#elif defined(__OS2__)
|
||||
DosFreeModule ((HMODULE)handle);
|
||||
#elif defined(__DOS__) && defined(QSE_ENABLE_DOS_DYNAMIC_MODULE)
|
||||
FreeModule (handle);
|
||||
#elif defined(USE_DLFCN)
|
||||
dlclose (handle);
|
||||
#else
|
||||
/* nothing to do */
|
||||
#endif
|
||||
}
|
||||
|
||||
static void* mod_symbol (qse_httpd_t* httpd, void* handle, const qse_char_t* name)
|
||||
{
|
||||
void* s;
|
||||
qse_mchar_t* mname;
|
||||
|
||||
#if defined(QSE_CHAR_IS_MCHAR)
|
||||
mname = name;
|
||||
#else
|
||||
mname = qse_wcstombsdup (name, QSE_NULL, qse_httpd_getmmgr(httpd));
|
||||
if (!mname)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM);
|
||||
return QSE_NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(USE_LTDL)
|
||||
s = lt_dlsym (handle, mname);
|
||||
if (s == QSE_NULL) qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||
#elif defined(_WIN32)
|
||||
s = GetProcAddress ((HMODULE)handle, mname);
|
||||
if (s == QSE_NULL) qse_httpd_seterrnum (httpd, syserr_to_errnum(GetLastError()));
|
||||
#elif defined(__OS2__)
|
||||
{
|
||||
APIRET rc;
|
||||
rc = DosQueryProcAddr ((HMODULE)handle, 0, mname, (PFN*)&s);
|
||||
if (rc != NO_ERROR)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, syserr_to_errnum(rc));
|
||||
s = QSE_NULL;
|
||||
}
|
||||
}
|
||||
#elif defined(__DOS__) && defined(QSE_ENABLE_DOS_DYNAMIC_MODULE)
|
||||
s = GetProcAddress (handle, mname);
|
||||
if (s == QSE_NULL) qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
|
||||
#elif defined(USE_DLFCN)
|
||||
s = dlsym (handle, mname);
|
||||
if (s == QSE_NULL) qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR);
|
||||
#else
|
||||
s = QSE_NULL;
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL);
|
||||
#endif
|
||||
|
||||
#if defined(QSE_CHAR_IS_MCHAR)
|
||||
/* nothing to do */
|
||||
#else
|
||||
QSE_MMGR_FREE (qse_httpd_getmmgr(httpd), mname);
|
||||
#endif
|
||||
|
||||
return s;
|
||||
}
|
||||
|
642
lib/http/httpd-std-urs.h
Normal file
642
lib/http/httpd-std-urs.h
Normal file
@ -0,0 +1,642 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file holds url rewriting support code and is included by httpd-std.c
|
||||
*/
|
||||
|
||||
#define URS_SEQ_RANGE_SIZE (QSE_TYPE_MAX(qse_uint16_t) - 2)
|
||||
#define URS_MAX_URL_LEN 50000
|
||||
|
||||
typedef struct urs_hdr_t urs_hdr_t;
|
||||
typedef struct urs_pkt_t urs_pkt_t;
|
||||
typedef struct urs_ctx_t urs_ctx_t;
|
||||
typedef struct urs_req_t urs_req_t;
|
||||
|
||||
#include <qse/pack1.h>
|
||||
struct urs_hdr_t
|
||||
{
|
||||
qse_uint16_t seq; /* in network-byte order */
|
||||
qse_uint16_t rcode; /* response code */
|
||||
qse_uint32_t urlsum; /* checksum of url in the request */
|
||||
qse_uint16_t pktlen; /* packet header size + url length */
|
||||
};
|
||||
|
||||
struct urs_pkt_t
|
||||
{
|
||||
struct urs_hdr_t hdr;
|
||||
qse_mchar_t url[1];
|
||||
};
|
||||
#include <qse/unpack.h>
|
||||
|
||||
struct urs_ctx_t
|
||||
{
|
||||
qse_httpd_t* httpd;
|
||||
qse_httpd_urs_t* urs;
|
||||
|
||||
qse_skad_t skad;
|
||||
int skadlen;
|
||||
int urs_socket; /* default urs socket to use */
|
||||
|
||||
qse_uint16_t seq; /* TODO: change to uint32_t??? */
|
||||
urs_req_t* reqs[1024]; /* TOOD: choose the right size */
|
||||
qse_uint16_t req_count;
|
||||
|
||||
qse_uint8_t rcvbuf[QSE_SIZEOF(urs_hdr_t) + URS_MAX_URL_LEN + 1];
|
||||
qse_uint8_t fmtbuf[QSE_SIZEOF(urs_hdr_t) + URS_MAX_URL_LEN + 1];
|
||||
|
||||
#if defined(AF_UNIX)
|
||||
struct sockaddr_un unix_bind_addr;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct urs_req_t
|
||||
{
|
||||
qse_uint16_t seq; /* in host-byte order */
|
||||
qse_uint32_t pktlen;
|
||||
urs_pkt_t* pkt;
|
||||
|
||||
qse_httpd_rewrite_t rewrite;
|
||||
void* ctx;
|
||||
|
||||
urs_ctx_t* dc;
|
||||
qse_skad_t urs_skad;
|
||||
int urs_skadlen;
|
||||
int urs_socket;
|
||||
int urs_retries;
|
||||
qse_ntime_t urs_tmout;
|
||||
|
||||
qse_tmr_index_t tmr_tmout;
|
||||
|
||||
urs_req_t* prev;
|
||||
urs_req_t* next;
|
||||
};
|
||||
|
||||
|
||||
static int urs_open (qse_httpd_t* httpd, qse_httpd_urs_t* urs)
|
||||
{
|
||||
qse_nwad_t nwad;
|
||||
urs_ctx_t* dc;
|
||||
httpd_xtn_t* httpd_xtn = GET_HTTPD_XTN(httpd);
|
||||
int type, proto = 0; /*IPPROTO_UDP;*/ /*IPPROTO_SCTP*/
|
||||
|
||||
urs->handle[0] = QSE_INVALID_SCKHND;
|
||||
urs->handle[1] = QSE_INVALID_SCKHND;
|
||||
urs->handle[2] = QSE_INVALID_SCKHND;
|
||||
|
||||
dc = (urs_ctx_t*) qse_httpd_callocmem (httpd, QSE_SIZEOF(urs_ctx_t));
|
||||
if (dc == NULL) goto oops;
|
||||
|
||||
dc->httpd = httpd;
|
||||
dc->urs = urs;
|
||||
|
||||
nwad = httpd_xtn->urs.nwad;
|
||||
if (nwad.type != QSE_NWAD_NX && qse_getnwadport(&nwad) == 0)
|
||||
qse_setnwadport (&nwad, qse_hton16(QSE_HTTPD_URSSTD_DEFAULT_PORT));
|
||||
|
||||
#if defined(QSE_HTTPD_DEBUG)
|
||||
{
|
||||
qse_mchar_t tmp[128];
|
||||
qse_nwadtombs (&nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL);
|
||||
HTTPD_DBGOUT1 ("Default URS server set to [%hs]\n", tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(IPPROTO_SCTP)
|
||||
type = (proto == IPPROTO_SCTP)? SOCK_SEQPACKET: SOCK_DGRAM;
|
||||
#else
|
||||
type = SOCK_DGRAM;
|
||||
#endif
|
||||
|
||||
urs->handle[0] = open_client_socket (httpd, AF_INET, type, proto);
|
||||
#if defined(AF_INET6)
|
||||
urs->handle[1] = open_client_socket (httpd, AF_INET6, type, proto);
|
||||
#endif
|
||||
#if defined(AF_UNIX)
|
||||
urs->handle[2] = open_client_socket (httpd, AF_UNIX, type, 0);
|
||||
#endif
|
||||
|
||||
if (qse_is_sck_valid(urs->handle[2]))
|
||||
{
|
||||
#if defined(AF_UNIX)
|
||||
qse_ntime_t now;
|
||||
|
||||
qse_gettime (&now);
|
||||
|
||||
QSE_MEMSET (&dc->unix_bind_addr, 0, QSE_SIZEOF(dc->unix_bind_addr));
|
||||
dc->unix_bind_addr.sun_family = AF_UNIX;
|
||||
|
||||
/* TODO: make the location(/tmp) or the prefix(.urs-) of the socket file configurable??? */
|
||||
qse_mbsxfmt (
|
||||
dc->unix_bind_addr.sun_path,
|
||||
QSE_COUNTOF(dc->unix_bind_addr.sun_path),
|
||||
QSE_MT("/tmp/.urs-%x-%lu"), (int)QSE_GETPID(), (unsigned long int)urs->handle[2]);
|
||||
QSE_UNLINK (dc->unix_bind_addr.sun_path);
|
||||
if (bind (urs->handle[2], (struct sockaddr*)&dc->unix_bind_addr, QSE_SIZEOF(dc->unix_bind_addr)) <= -1)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
|
||||
qse_close_sck (urs->handle[2]);
|
||||
urs->handle[2] = QSE_INVALID_SCKHND;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!qse_is_sck_valid(urs->handle[0]) &&
|
||||
!qse_is_sck_valid(urs->handle[1]) &&
|
||||
!qse_is_sck_valid(urs->handle[2]))
|
||||
{
|
||||
/* don't set the error number here.
|
||||
* open_client_socket() or bind() above should set the error number */
|
||||
goto oops;
|
||||
}
|
||||
|
||||
/* carry on regardless of success or failure */
|
||||
dc->skadlen = qse_nwadtoskad (&nwad, &dc->skad);
|
||||
|
||||
/* determine which socket to use when sending a request to the default server */
|
||||
if (dc->skadlen >= 0)
|
||||
{
|
||||
switch (nwad.type)
|
||||
{
|
||||
case QSE_NWAD_IN4:
|
||||
dc->urs_socket = urs->handle[0];
|
||||
break;
|
||||
case QSE_NWAD_IN6:
|
||||
dc->urs_socket = urs->handle[1];
|
||||
break;
|
||||
case QSE_NWAD_LOCAL:
|
||||
dc->urs_socket = urs->handle[2];
|
||||
break;
|
||||
default:
|
||||
/* unsupported address for the default server */
|
||||
dc->urs_socket = QSE_INVALID_SCKHND;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dc->urs_socket = QSE_INVALID_SCKHND;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (proto == IPPROTO_SCTP)
|
||||
{
|
||||
/* TODO: error handling */
|
||||
if (qse_is_sck_valid(urs->handle[0])) listen (urs->handle[0], 99);
|
||||
if (qse_is_sck_valid(urs->handle[1])) listen (urs->handle[1], 99);
|
||||
/* handle[2] is a unix socket. no special handling for SCTP */
|
||||
}
|
||||
#endif
|
||||
|
||||
urs->handle_count = 3;
|
||||
if (qse_is_sck_valid(urs->handle[0])) urs->handle_mask |= (1 << 0);
|
||||
if (qse_is_sck_valid(urs->handle[1])) urs->handle_mask |= (1 << 1);
|
||||
if (qse_is_sck_valid(urs->handle[2])) urs->handle_mask |= (1 << 2);
|
||||
|
||||
urs->ctx = dc;
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
if (qse_is_sck_valid(urs->handle[0])) qse_close_sck (urs->handle[0]);
|
||||
if (qse_is_sck_valid(urs->handle[1])) qse_close_sck (urs->handle[1]);
|
||||
if (qse_is_sck_valid(urs->handle[2]))
|
||||
{
|
||||
qse_close_sck (urs->handle[2]);
|
||||
#if defined(AF_UNIX)
|
||||
QSE_UNLINK (dc->unix_bind_addr.sun_path);
|
||||
#endif
|
||||
}
|
||||
if (dc) qse_httpd_freemem (httpd, dc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void urs_remove_tmr_tmout (qse_httpd_t* httpd, urs_req_t* req)
|
||||
{
|
||||
if (req->tmr_tmout != QSE_TMR_INVALID_INDEX)
|
||||
{
|
||||
qse_httpd_remove_timer_event (httpd, req->tmr_tmout);
|
||||
req->tmr_tmout = QSE_TMR_INVALID_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
static void urs_close (qse_httpd_t* httpd, qse_httpd_urs_t* urs)
|
||||
{
|
||||
urs_ctx_t* dc = (urs_ctx_t*)urs->ctx;
|
||||
qse_size_t i;
|
||||
|
||||
for (i = 0; i < QSE_COUNTOF(dc->reqs); i++)
|
||||
{
|
||||
urs_req_t* next_req;
|
||||
while (dc->reqs[i])
|
||||
{
|
||||
next_req = dc->reqs[i]->next;
|
||||
urs_remove_tmr_tmout (httpd, dc->reqs[i]);
|
||||
qse_httpd_freemem (httpd, dc->reqs[i]);
|
||||
dc->reqs[i] = next_req;
|
||||
dc->req_count--;
|
||||
}
|
||||
}
|
||||
|
||||
QSE_ASSERT (dc->req_count == 0);
|
||||
|
||||
if (qse_is_sck_valid(urs->handle[0])) qse_close_sck (urs->handle[0]);
|
||||
if (qse_is_sck_valid(urs->handle[1])) qse_close_sck (urs->handle[1]);
|
||||
if (qse_is_sck_valid(urs->handle[2]))
|
||||
{
|
||||
qse_close_sck (urs->handle[2]);
|
||||
#if defined(AF_UNIX)
|
||||
QSE_UNLINK (dc->unix_bind_addr.sun_path);
|
||||
#endif
|
||||
}
|
||||
qse_httpd_freemem (httpd, urs->ctx);
|
||||
}
|
||||
|
||||
|
||||
static int urs_recv (qse_httpd_t* httpd, qse_httpd_urs_t* urs, qse_httpd_hnd_t handle)
|
||||
{
|
||||
urs_ctx_t* dc = (urs_ctx_t*)urs->ctx;
|
||||
/*httpd_xtn_t* httpd_xtn = GET_HTTPD_XTN(httpd);*/
|
||||
|
||||
qse_skad_t fromaddr;
|
||||
qse_sck_len_t fromlen;
|
||||
|
||||
qse_uint16_t xid;
|
||||
qse_ssize_t len, url_len;
|
||||
urs_pkt_t* pkt;
|
||||
urs_req_t* req;
|
||||
qse_mchar_t* spc;
|
||||
|
||||
/* TODO: use recvmsg with MSG_ERRQUEUE... set socket option IP_RECVERR... */
|
||||
fromlen = QSE_SIZEOF(fromaddr);
|
||||
len = recvfrom (handle, dc->rcvbuf, QSE_SIZEOF(dc->rcvbuf) - 1, 0, (struct sockaddr*)&fromaddr, &fromlen);
|
||||
|
||||
/* TODO: check if fromaddr matches the dc->skad... */
|
||||
|
||||
pkt = (urs_pkt_t*)dc->rcvbuf;
|
||||
if (len >= QSE_SIZEOF(urs_hdr_t))
|
||||
{
|
||||
pkt->hdr.pktlen = qse_ntoh16(pkt->hdr.pktlen);
|
||||
if (len == pkt->hdr.pktlen)
|
||||
{
|
||||
url_len = pkt->hdr.pktlen - QSE_SIZEOF(urs_hdr_t);
|
||||
xid = qse_ntoh16(pkt->hdr.seq) % QSE_COUNTOF(dc->reqs);
|
||||
|
||||
for (req = dc->reqs[xid]; req; req = req->next)
|
||||
{
|
||||
if (req->pkt->hdr.seq == pkt->hdr.seq && req->pkt->hdr.urlsum == pkt->hdr.urlsum)
|
||||
{
|
||||
/* null-terminate the url for easier processing */
|
||||
pkt->url[url_len] = QSE_MT('\0');
|
||||
|
||||
/* drop trailers starting from the first space onwards */
|
||||
spc = qse_mbschr (pkt->url, QSE_MT(' '));
|
||||
if (spc) *spc = QSE_MT('\0');
|
||||
|
||||
urs_remove_tmr_tmout (httpd, req);
|
||||
req->rewrite (httpd, req->pkt->url, pkt->url, req->ctx);
|
||||
|
||||
/* detach the request off dc->reqs */
|
||||
if (req == dc->reqs[xid]) dc->reqs[xid] = req->next;
|
||||
else req->prev->next = req->next;
|
||||
if (req->next) req->next->prev = req->prev;
|
||||
|
||||
qse_httpd_freemem (httpd, req);
|
||||
dc->req_count--;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tmr_urs_tmout_update (qse_tmr_t* tmr, qse_tmr_index_t old_index, qse_tmr_index_t new_index, qse_tmr_event_t* evt)
|
||||
{
|
||||
urs_req_t* req = (urs_req_t*)evt->ctx;
|
||||
|
||||
QSE_ASSERT (req->tmr_tmout == old_index);
|
||||
req->tmr_tmout = new_index;
|
||||
}
|
||||
|
||||
static void tmr_urs_tmout_handle (qse_tmr_t* tmr, const qse_ntime_t* now, qse_tmr_event_t* evt)
|
||||
{
|
||||
/* destory the unanswered request if timed out */
|
||||
|
||||
urs_req_t* req = (urs_req_t*)evt->ctx;
|
||||
urs_ctx_t* dc = req->dc;
|
||||
qse_uint16_t xid;
|
||||
|
||||
/* when this handler is called, the event should be removed from the timer */
|
||||
QSE_ASSERT (req->tmr_tmout == QSE_TMR_INVALID_INDEX);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* resend
|
||||
*---------------------------------------------------------------- */
|
||||
if (req->urs_retries > 0)
|
||||
{
|
||||
/*httpd_xtn_t* httpd_xtn = GET_HTTPD_XTN(dc->httpd);*/
|
||||
qse_tmr_event_t tmout_event;
|
||||
|
||||
QSE_MEMSET (&tmout_event, 0, QSE_SIZEOF(tmout_event));
|
||||
qse_gettime (&tmout_event.when);
|
||||
qse_add_ntime (&tmout_event.when, &req->urs_tmout, &tmout_event.when);
|
||||
tmout_event.ctx = req;
|
||||
tmout_event.handler = tmr_urs_tmout_handle;
|
||||
tmout_event.updater = tmr_urs_tmout_update;
|
||||
|
||||
if (sendto (req->urs_socket, (void*)req->pkt, req->pktlen, 0, (struct sockaddr*)&req->urs_skad, req->urs_skadlen) != req->pktlen)
|
||||
{
|
||||
/* error. fall thru */
|
||||
qse_httpd_seterrnum (dc->httpd, SKERR_TO_ERRNUM());
|
||||
|
||||
/* Unix datagram socket seems to fail with EAGAIN often
|
||||
* even with increased SO_SNDBUF size. */
|
||||
if (dc->httpd->errnum == QSE_HTTPD_EAGAIN && req->urs_retries > 1)
|
||||
{
|
||||
/* TODO: check writability of req->urs_socket instead of just retrying... */
|
||||
goto send_ok;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
send_ok:
|
||||
QSE_ASSERT (tmr == dc->httpd->tmr);
|
||||
if (qse_httpd_insert_timer_event (dc->httpd, &tmout_event, &req->tmr_tmout) >= 0)
|
||||
{
|
||||
req->urs_retries--;
|
||||
return; /* resend ok */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf ("urs timed out....\n");
|
||||
/* ---------------------------------------------------------------
|
||||
* timed out + no resend
|
||||
*---------------------------------------------------------------- */
|
||||
xid = req->seq % QSE_COUNTOF(dc->reqs);
|
||||
|
||||
/* detach the request off dc->reqs */
|
||||
if (req == dc->reqs[xid]) dc->reqs[xid] = req->next;
|
||||
else req->prev->next = req->next;
|
||||
if (req->next) req->next->prev = req->prev;
|
||||
|
||||
/* urs timed out. report that name resolution failed */
|
||||
req->rewrite (dc->httpd, req->pkt->url, QSE_NULL, req->ctx);
|
||||
|
||||
/* i don't cache the items that have timed out */
|
||||
qse_httpd_freemem (dc->httpd, req);
|
||||
dc->req_count--;
|
||||
}
|
||||
|
||||
static int urs_send (qse_httpd_t* httpd, qse_httpd_urs_t* urs, const qse_mchar_t* url, qse_httpd_rewrite_t rewrite, const qse_httpd_urs_server_t* urs_server, void* ctx)
|
||||
{
|
||||
urs_ctx_t* dc = (urs_ctx_t*)urs->ctx;
|
||||
httpd_xtn_t* httpd_xtn = GET_HTTPD_XTN(httpd);
|
||||
|
||||
qse_uint16_t xid;
|
||||
qse_uint32_t seq;
|
||||
urs_req_t* req = QSE_NULL;
|
||||
qse_size_t url_len;
|
||||
qse_tmr_event_t tmout_event;
|
||||
|
||||
if (dc->req_count >= QSE_COUNTOF(dc->reqs))
|
||||
{
|
||||
/* too many pending requests */
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOBUF);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
url_len = qse_mbslen(url);
|
||||
if (url_len > URS_MAX_URL_LEN) /* TODO: change the limit */
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
seq = ((qse_uint32_t)dc->seq + 1) % URS_SEQ_RANGE_SIZE;
|
||||
dc->seq = seq;
|
||||
|
||||
xid = seq % QSE_COUNTOF(dc->reqs);
|
||||
|
||||
req = qse_httpd_callocmem (httpd, QSE_SIZEOF(*req) + QSE_SIZEOF(urs_hdr_t) + url_len + 1);
|
||||
if (req == QSE_NULL) goto oops;
|
||||
|
||||
req->tmr_tmout = QSE_TMR_INVALID_INDEX;
|
||||
req->seq = seq;
|
||||
req->pkt = (urs_pkt_t*)(req + 1);
|
||||
req->pktlen = QSE_SIZEOF(urs_hdr_t) + url_len;
|
||||
|
||||
req->pkt->hdr.seq = qse_hton16(seq);
|
||||
req->pkt->hdr.pktlen = qse_hton16(req->pktlen);
|
||||
req->pkt->hdr.urlsum = hash_string (url);
|
||||
qse_mbscpy (req->pkt->url, url);
|
||||
|
||||
req->rewrite = rewrite;
|
||||
req->ctx = ctx;
|
||||
|
||||
req->urs_retries = httpd_xtn->urs.retries;
|
||||
req->urs_tmout = httpd_xtn->urs.tmout;
|
||||
|
||||
if (urs_server)
|
||||
{
|
||||
if (urs_server->retries >= 0) req->urs_retries = urs_server->retries;
|
||||
if (urs_server->tmout.sec >= 0) req->urs_tmout = urs_server->tmout;
|
||||
|
||||
req->urs_skadlen = qse_nwadtoskad (&urs_server->nwad, &req->urs_skad);
|
||||
if (req->urs_skadlen <= -1) goto default_urs_server;
|
||||
|
||||
switch (urs_server->nwad.type)
|
||||
{
|
||||
case QSE_NWAD_IN4:
|
||||
req->urs_socket = urs->handle[0];
|
||||
break;
|
||||
case QSE_NWAD_IN6:
|
||||
req->urs_socket = urs->handle[1];
|
||||
break;
|
||||
case QSE_NWAD_LOCAL:
|
||||
req->urs_socket = urs->handle[2];
|
||||
break;
|
||||
default:
|
||||
/* TODO: should it return failure with QSE_HTTPD_EINVAL? */
|
||||
goto default_urs_server;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
default_urs_server:
|
||||
if (dc->skadlen >= 0)
|
||||
{
|
||||
/* the default url rewrite server address set in urs_open
|
||||
* is valid. */
|
||||
req->urs_skad = dc->skad;
|
||||
req->urs_skadlen = dc->skadlen;
|
||||
req->urs_socket = dc->urs_socket;
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOURS);
|
||||
goto oops;
|
||||
}
|
||||
}
|
||||
|
||||
QSE_MEMSET (&tmout_event, 0, QSE_SIZEOF(tmout_event));
|
||||
qse_gettime (&tmout_event.when);
|
||||
qse_add_ntime (&tmout_event.when, &req->urs_tmout, &tmout_event.when);
|
||||
tmout_event.ctx = req;
|
||||
tmout_event.handler = tmr_urs_tmout_handle;
|
||||
tmout_event.updater = tmr_urs_tmout_update;
|
||||
if (qse_httpd_insert_timer_event (httpd, &tmout_event, &req->tmr_tmout) <= -1) goto oops;
|
||||
|
||||
/*
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
QSE_MEMSET (&msg, 0, QSE_SIZEOF(msg));
|
||||
msg.msg_name = &req->urs_skad;
|
||||
msg.msg_namelen = req->urs_skadlen;
|
||||
iov.iov_base = req->pkt;
|
||||
iov.iov_len = req->pktlen;
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
if (sendmsg (req->urs_socket, &msg, 0) != req->pktlen)
|
||||
}
|
||||
*/
|
||||
|
||||
if (sendto (req->urs_socket, (void*)req->pkt, req->pktlen, 0, (struct sockaddr*)&req->urs_skad, req->urs_skadlen) != req->pktlen)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
|
||||
printf ("URS SENDTO FAILURE........................\n"); /* TODO: logging */
|
||||
|
||||
/* Unix datagram socket seems to fail with EAGAIN often
|
||||
* even with increased SO_SNDBUF size. */
|
||||
if (httpd->errnum == QSE_HTTPD_EAGAIN && req->urs_retries > 0)
|
||||
{
|
||||
/* TODO: check writability of req->urs_socket instead of just retrying... */
|
||||
goto send_ok;
|
||||
}
|
||||
|
||||
goto oops;
|
||||
}
|
||||
|
||||
send_ok:
|
||||
req->dc = dc;
|
||||
|
||||
/* link the request to the front of the chain */
|
||||
if (dc->reqs[xid]) dc->reqs[xid]->prev = req;
|
||||
req->next = dc->reqs[xid];
|
||||
dc->reqs[xid] = req;
|
||||
|
||||
/* increment the number of pending requests */
|
||||
dc->req_count++;
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
if (req)
|
||||
{
|
||||
urs_remove_tmr_tmout (httpd, req);
|
||||
qse_httpd_freemem (httpd, req);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int urs_prerewrite (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, const qse_mchar_t* host, qse_mchar_t** url)
|
||||
{
|
||||
const qse_mchar_t* qpath;
|
||||
int mtype;
|
||||
const qse_mchar_t* mname;
|
||||
const qse_mchar_t* quest;
|
||||
const qse_mchar_t* qparam;
|
||||
const qse_mchar_t* proto;
|
||||
|
||||
const qse_mchar_t* host_ptr = QSE_NULL;
|
||||
qse_mchar_t cliaddrbuf[MAX_NWAD_TEXT_SIZE];
|
||||
qse_size_t total_len;
|
||||
qse_mchar_t* url_to_rewrite;
|
||||
|
||||
qpath = qse_htre_getqpath(req);
|
||||
qparam = qse_htre_getqparam(req);
|
||||
mtype = qse_htre_getqmethodtype(req);
|
||||
mname = qse_htre_getqmethodname(req);
|
||||
|
||||
total_len = qse_mbslen(qpath) + qse_mbslen(mname);
|
||||
if (qparam)
|
||||
{
|
||||
quest = QSE_MT("?");
|
||||
total_len = total_len + 1 + qse_mbslen(qparam);
|
||||
}
|
||||
else
|
||||
{
|
||||
qparam = QSE_MT("");
|
||||
quest = QSE_MT("");
|
||||
}
|
||||
|
||||
if (host)
|
||||
{
|
||||
/* use the host name set explicitly by the caller */
|
||||
host_ptr = host;
|
||||
total_len += qse_mbslen(host_ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* find the host name in the http header */
|
||||
const qse_htre_hdrval_t* hosthv;
|
||||
hosthv = qse_htre_getheaderval(req, QSE_MT("Host"));
|
||||
if (hosthv)
|
||||
{
|
||||
/* the first host header only */
|
||||
host_ptr = hosthv->ptr;
|
||||
total_len += hosthv->len;
|
||||
}
|
||||
}
|
||||
|
||||
total_len += qse_nwadtombs (&client->remote_addr, cliaddrbuf, QSE_COUNTOF(cliaddrbuf), QSE_NWADTOMBS_ADDR);
|
||||
total_len += 128; /* extra space */
|
||||
|
||||
url_to_rewrite = qse_httpd_allocmem (httpd, total_len);
|
||||
if (url_to_rewrite == QSE_NULL) return -1;
|
||||
|
||||
if (mtype == QSE_HTTP_CONNECT || !host_ptr)
|
||||
{
|
||||
host_ptr = QSE_MT("");
|
||||
proto = QSE_MT("");
|
||||
}
|
||||
else if (client->status & QSE_HTTPD_CLIENT_SECURE)
|
||||
{
|
||||
proto = QSE_MT("https://");
|
||||
}
|
||||
else
|
||||
{
|
||||
proto = QSE_MT("http://");
|
||||
}
|
||||
|
||||
/* URL client-ip/client-fqdn ident method */
|
||||
qse_mbsxfmt (url_to_rewrite, total_len, QSE_MT("%s%s%s%s%s %s/- - %s"), proto, host_ptr, qpath, quest, qparam, cliaddrbuf, mname);
|
||||
|
||||
*url = url_to_rewrite;
|
||||
return 1;
|
||||
}
|
3781
lib/http/httpd-std.c
Normal file
3781
lib/http/httpd-std.c
Normal file
File diff suppressed because it is too large
Load Diff
422
lib/http/httpd-task.c
Normal file
422
lib/http/httpd-task.c
Normal file
@ -0,0 +1,422 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "httpd.h"
|
||||
#include <qse/cmn/str.h>
|
||||
#include "../cmn/mem-prv.h"
|
||||
|
||||
/* TODO:
|
||||
* many functions in this file use qse_size_t.
|
||||
* so the size data transfers is limited by this type.
|
||||
* break this barrier... */
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
static int task_main_disconnect (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
httpd->opt.scb.client.shutdown (httpd, client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entaskdisconnect (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred)
|
||||
{
|
||||
qse_httpd_task_t task;
|
||||
|
||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||
task.main = task_main_disconnect;
|
||||
|
||||
return qse_httpd_entask (httpd, client, pred, &task, 0);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/* TODO: send wide character string when QSE_CHAR_IS_WCHAR */
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
typedef struct task_format_t task_format_t;
|
||||
struct task_format_t
|
||||
{
|
||||
qse_mchar_t* org;
|
||||
const qse_mchar_t* ptr;
|
||||
qse_size_t left;
|
||||
};
|
||||
|
||||
static int task_init_format (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_format_t* xtn = qse_httpd_gettaskxtn (httpd, task);
|
||||
|
||||
QSE_MEMCPY (xtn, task->ctx, QSE_SIZEOF(*xtn));
|
||||
task->ctx = xtn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void task_fini_format (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
task_format_t* ctx = (task_format_t*)task->ctx;
|
||||
qse_httpd_freemem (httpd, ctx->org);
|
||||
}
|
||||
|
||||
static int task_main_format (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
|
||||
{
|
||||
qse_ssize_t n;
|
||||
qse_size_t count;
|
||||
task_format_t* ctx = (task_format_t*)task->ctx;
|
||||
|
||||
count = MAX_SEND_SIZE;
|
||||
if (count >= ctx->left) count = ctx->left;
|
||||
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->opt.scb.client.send (httpd, client, ctx->ptr, count);
|
||||
if (n <= -1)
|
||||
{
|
||||
if (httpd->errnum != QSE_HTTPD_EAGAIN) return -1;
|
||||
}
|
||||
else if (n > 0)
|
||||
{
|
||||
ctx->left -= n;
|
||||
if (ctx->left <= 0) return 0;
|
||||
ctx->ptr += n;
|
||||
}
|
||||
|
||||
return 1; /* more work to do */
|
||||
}
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entaskformat (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred,
|
||||
const qse_mchar_t* fmt, ...)
|
||||
{
|
||||
qse_httpd_task_t task;
|
||||
task_format_t data;
|
||||
|
||||
va_list ap;
|
||||
qse_mchar_t* buf;
|
||||
int bytes_req, l;
|
||||
|
||||
va_start (ap, fmt);
|
||||
bytes_req = qse_mbsxvfmt (QSE_NULL, 0, fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
buf = (qse_mchar_t*) qse_httpd_allocmem (
|
||||
httpd, (bytes_req + 1) * QSE_SIZEOF(*buf));
|
||||
if (buf == QSE_NULL) return QSE_NULL;
|
||||
|
||||
va_start (ap, fmt);
|
||||
l = qse_mbsxvfmt (buf, bytes_req + 1, fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
if (l != bytes_req)
|
||||
{
|
||||
/* something got wrong ... */
|
||||
qse_httpd_freemem (httpd, buf);
|
||||
httpd->errnum = QSE_HTTPD_EINTERN;
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||
data.org = buf;
|
||||
data.ptr = buf;
|
||||
data.left = l;
|
||||
|
||||
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
|
||||
task.init = task_init_format;
|
||||
task.fini = task_fini_format;
|
||||
task.main = task_main_format;
|
||||
task.ctx = &data;
|
||||
|
||||
return qse_httpd_entask (
|
||||
httpd, client, pred, &task, QSE_SIZEOF(data));
|
||||
}
|
||||
|
||||
/* TODO: send wide character string when QSE_CHAR_IS_WCHAR */
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entask_status (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred, int code, void* extra,
|
||||
qse_http_method_t method, const qse_http_version_t* version,
|
||||
int keepalive)
|
||||
{
|
||||
const qse_mchar_t* msg;
|
||||
|
||||
const qse_mchar_t* extrapre = QSE_MT("");
|
||||
const qse_mchar_t* extrapst = QSE_MT("");
|
||||
const qse_mchar_t* extraval = QSE_MT("");
|
||||
|
||||
qse_mchar_t text[1024]; /* TODO: make this buffer dynamic or scalable */
|
||||
|
||||
text[0] = QSE_MT('\0');
|
||||
|
||||
msg = qse_httpstatustombs (code);
|
||||
switch (code)
|
||||
{
|
||||
case 301: /* Moved Permanently */
|
||||
case 302: /* Found */
|
||||
case 303: /* See Other (since HTTP/1.1) */
|
||||
case 307: /* Temporary Redirect (since HTTP/1.1) */
|
||||
case 308: /* Permanent Redirect (Experimental RFC; RFC 7238) */
|
||||
{
|
||||
qse_httpd_rsrc_reloc_t* reloc;
|
||||
reloc = (qse_httpd_rsrc_reloc_t*)extra;
|
||||
extrapre = QSE_MT("Location: ");
|
||||
extrapst = (reloc->flags & QSE_HTTPD_RSRC_RELOC_APPENDSLASH)? QSE_MT("/\r\n"): QSE_MT("\r\n");
|
||||
extraval = reloc->target;
|
||||
break;
|
||||
}
|
||||
|
||||
case 304:
|
||||
case 200:
|
||||
case 201:
|
||||
case 202:
|
||||
case 203:
|
||||
case 204:
|
||||
case 205:
|
||||
case 206:
|
||||
/* nothing to do */
|
||||
break;
|
||||
|
||||
default:
|
||||
if (method != QSE_HTTP_HEAD &&
|
||||
httpd->opt.rcb.fmterr (httpd, client, code, text, QSE_COUNTOF(text)) <= -1) return QSE_NULL;
|
||||
|
||||
if (code == 401)
|
||||
{
|
||||
extrapre = QSE_MT("WWW-Authenticate: Basic realm=\"");
|
||||
extrapst = QSE_MT("\"\r\n");
|
||||
extraval = (const qse_mchar_t*)extra;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return qse_httpd_entaskformat (
|
||||
httpd, client, pred,
|
||||
QSE_MT("HTTP/%d.%d %d %s\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nContent-Type: text/html\r\nContent-Length: %u\r\n%s%s%s\r\n%s"),
|
||||
version->major, version->minor,
|
||||
code, msg, qse_httpd_getname (httpd),
|
||||
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
|
||||
(keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
|
||||
(unsigned int)qse_mbslen(text), /* unsigned int should be large enough since text is small */
|
||||
extrapre, extraval, extrapst, text);
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entaskerrorwithmvk (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred, int code,
|
||||
qse_http_method_t method,
|
||||
const qse_http_version_t* version,
|
||||
int keepalive)
|
||||
{
|
||||
return qse_httpd_entask_status (httpd, client, pred, code, QSE_NULL, method, version, keepalive);
|
||||
}
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entaskerror (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred, int code, qse_htre_t* req)
|
||||
{
|
||||
return qse_httpd_entask_status (
|
||||
httpd, client, pred, code, QSE_NULL,
|
||||
qse_htre_getqmethodtype(req),
|
||||
qse_htre_getversion(req),
|
||||
(req->flags & QSE_HTRE_ATTR_KEEPALIVE)
|
||||
);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
qse_httpd_task_t* qse_httpd_entaskcontinue (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred, qse_htre_t* req)
|
||||
{
|
||||
const qse_http_version_t* version = qse_htre_getversion(req);
|
||||
return qse_httpd_entaskformat (
|
||||
httpd, client, pred,
|
||||
QSE_MT("HTTP/%d.%d 100 Continue\r\n\r\n"),
|
||||
version->major, version->minor);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entaskauth (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred, const qse_mchar_t* realm, qse_htre_t* req)
|
||||
{
|
||||
return qse_httpd_entask_status (
|
||||
httpd, client, pred, 401, (void*)realm,
|
||||
qse_htre_getqmethodtype(req),
|
||||
qse_htre_getversion(req),
|
||||
(req->flags & QSE_HTRE_ATTR_KEEPALIVE));
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entaskreloc (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred, const qse_httpd_rsrc_reloc_t* reloc, qse_htre_t* req)
|
||||
{
|
||||
int code;
|
||||
|
||||
if (reloc->flags & QSE_HTTPD_RSRC_RELOC_KEEPMETHOD)
|
||||
{
|
||||
code = (reloc->flags & QSE_HTTPD_RSRC_RELOC_PERMANENT)? 308: 307;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* NOTE: 302 can be 303 for HTTP/1.1 */
|
||||
code = (reloc->flags & QSE_HTTPD_RSRC_RELOC_PERMANENT)? 301: 302;
|
||||
}
|
||||
|
||||
return qse_httpd_entask_status (
|
||||
httpd, client, pred, code, (void*)reloc,
|
||||
qse_htre_getqmethodtype(req),
|
||||
qse_htre_getversion(req),
|
||||
(req->flags & QSE_HTRE_ATTR_KEEPALIVE));
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entask_nomod (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* pred,
|
||||
qse_http_method_t method, const qse_http_version_t* version, int keepalive)
|
||||
{
|
||||
return qse_httpd_entask_status (
|
||||
httpd, client, pred, 304, QSE_NULL, method, version, keepalive);
|
||||
}
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entasknomod (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred, qse_htre_t* req)
|
||||
{
|
||||
return qse_httpd_entask_status (
|
||||
httpd, client, pred, 304, QSE_NULL,
|
||||
qse_htre_getqmethodtype(req),
|
||||
qse_htre_getversion(req),
|
||||
(req->flags & QSE_HTRE_ATTR_KEEPALIVE));
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entaskallow (
|
||||
qse_httpd_t* httpd, qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred, const qse_mchar_t* allow, qse_htre_t* req)
|
||||
{
|
||||
int code = 200;
|
||||
const qse_mchar_t* msg;
|
||||
const qse_http_version_t* version;
|
||||
int keepalive;
|
||||
|
||||
msg = qse_httpstatustombs (code);
|
||||
version = qse_htre_getversion(req);
|
||||
keepalive = (req->flags & QSE_HTRE_ATTR_KEEPALIVE);
|
||||
return qse_httpd_entaskformat (
|
||||
httpd, client, pred,
|
||||
QSE_MT("HTTP/%d.%d %d %s\r\nServer: %s\r\nDate: %s\r\nConnection: %s\r\nAllow: %s\r\nContent-Length: 0\r\n\r\n"),
|
||||
version->major, version->minor,
|
||||
code, msg, qse_httpd_getname (httpd),
|
||||
qse_httpd_fmtgmtimetobb (httpd, QSE_NULL, 0),
|
||||
(keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
|
||||
allow
|
||||
);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
#if 0
|
||||
qse_httpd_task_t* qse_httpd_entaskconnect (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred,
|
||||
const qse_nwad_t* nwad,
|
||||
qse_htre_t* req)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#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, pred, rsrc->u.auth.realm, req);
|
||||
break;
|
||||
|
||||
case QSE_HTTPD_RSRC_CGI:
|
||||
task = qse_httpd_entaskcgi (httpd, client, pred, &rsrc->u.cgi, req);
|
||||
break;
|
||||
|
||||
case QSE_HTTPD_RSRC_DIR:
|
||||
task = qse_httpd_entaskdir (httpd, client, pred, &rsrc->u.dir, req);
|
||||
break;
|
||||
|
||||
case QSE_HTTPD_RSRC_ERROR:
|
||||
task = qse_httpd_entaskerror (httpd, client, pred, rsrc->u.error.code, req);
|
||||
break;
|
||||
|
||||
case QSE_HTTPD_RSRC_FILE:
|
||||
task = qse_httpd_entaskfile (httpd, client, pred, rsrc->u.file.path, rsrc->u.file.mime, req);
|
||||
break;
|
||||
|
||||
case QSE_HTTPD_RSRC_PROXY:
|
||||
task = qse_httpd_entaskproxy (httpd, client, pred, &rsrc->u.proxy, req);
|
||||
break;
|
||||
|
||||
case QSE_HTTPD_RSRC_RELOC:
|
||||
task = qse_httpd_entaskreloc (httpd, client, pred, &rsrc->u.reloc, req);
|
||||
break;
|
||||
|
||||
case QSE_HTTPD_RSRC_TEXT:
|
||||
task = qse_httpd_entasktext (httpd, client, pred, 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;
|
||||
}
|
204
lib/http/httpd-text.c
Normal file
204
lib/http/httpd-text.c
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "httpd.h"
|
||||
#include "../cmn/mem-prv.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? */
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
n = httpd->opt.scb.client.send (httpd, client, ctx->ptr, count);
|
||||
if (n <= -1)
|
||||
{
|
||||
if (httpd->errnum != QSE_HTTPD_EAGAIN) return -1;
|
||||
}
|
||||
else if (n > 0)
|
||||
{
|
||||
ctx->left -= n;
|
||||
if (ctx->left <= 0) return 0;
|
||||
ctx->ptr += n;
|
||||
}
|
||||
|
||||
return 1; /* more work to do */
|
||||
}
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entasktextwithmvk (
|
||||
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_http_method_t method,
|
||||
const qse_http_version_t* version,
|
||||
int keepalive)
|
||||
{
|
||||
qse_size_t tlen;
|
||||
qse_mchar_t b_tlen[64];
|
||||
|
||||
qse_httpd_task_t task;
|
||||
task_text_t data;
|
||||
|
||||
switch (method)
|
||||
{
|
||||
case QSE_HTTP_HEAD:
|
||||
tlen = 0;
|
||||
break;
|
||||
|
||||
case QSE_HTTP_GET:
|
||||
case QSE_HTTP_POST:
|
||||
tlen = qse_mbslen(text);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Method not allowed */
|
||||
return qse_httpd_entaskerrorwithmvk (httpd, client, pred, 405, method, version, keepalive);
|
||||
}
|
||||
|
||||
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),
|
||||
(keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
|
||||
mime, b_tlen
|
||||
);
|
||||
if (pred == QSE_NULL) return QSE_NULL;
|
||||
|
||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||
data.ptr = text;
|
||||
data.left = tlen;
|
||||
|
||||
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_http_method_t method;
|
||||
qse_http_version_t* version;
|
||||
|
||||
|
||||
method = qse_htre_getqmethodtype (req);
|
||||
version = qse_htre_getversion (req);
|
||||
|
||||
qse_htre_discardcontent (req);
|
||||
return qse_httpd_entasktextwithmvk (httpd, client, pred, text, mime, method, version, (req->flags & QSE_HTRE_ATTR_KEEPALIVE));
|
||||
|
||||
#if 0
|
||||
qse_size_t tlen;
|
||||
qse_mchar_t b_tlen[64];
|
||||
qse_http_method_t method;
|
||||
qse_http_version_t* version;
|
||||
|
||||
qse_httpd_task_t task;
|
||||
task_text_t data;
|
||||
|
||||
method = qse_htre_getqmethodtype (req);
|
||||
version = qse_htre_getversion (req);
|
||||
|
||||
qse_htre_discardcontent (req);
|
||||
switch (method)
|
||||
{
|
||||
case QSE_HTTP_HEAD:
|
||||
tlen = 0;
|
||||
break;
|
||||
|
||||
case QSE_HTTP_GET:
|
||||
case QSE_HTTP_POST:
|
||||
tlen = qse_mbslen(text);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Method not allowed */
|
||||
return qse_httpd_entaskerror (httpd, client, pred, 405, req);
|
||||
}
|
||||
|
||||
qse_fmtuintmaxtombs (b_tlen, QSE_COUNTOF(b_tlen), tlen, 10, -1, QSE_MT('\0'), QSE_NULL);
|
||||
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->flags & QSE_HTRE_ATTR_KEEPALIVE)? QSE_MT("keep-alive"): QSE_MT("close")),
|
||||
mime, b_tlen
|
||||
);
|
||||
if (pred == QSE_NULL) return QSE_NULL;
|
||||
|
||||
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
|
||||
data.ptr = text;
|
||||
data.left = tlen;
|
||||
|
||||
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);
|
||||
#endif
|
||||
}
|
2369
lib/http/httpd.c
Normal file
2369
lib/http/httpd.c
Normal file
File diff suppressed because it is too large
Load Diff
220
lib/http/httpd.h
Normal file
220
lib/http/httpd.h
Normal file
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QSE_LIB_HTTP_HTTPD_H_
|
||||
#define _QSE_LIB_HTTP_HTTPD_H_
|
||||
|
||||
/* private header file for httpd */
|
||||
|
||||
#include <qse/http/httpd.h>
|
||||
|
||||
#if defined(NDEBUG)
|
||||
/* To include debugging messages while NDEBUG is set,
|
||||
* you can define QSE_HTTPD_DEBUG externally in CFLAGS or something.
|
||||
*/
|
||||
#else
|
||||
/* debugging mode */
|
||||
# define QSE_HTTPD_DEBUG 1
|
||||
#endif
|
||||
|
||||
#if defined(QSE_HTTPD_DEBUG)
|
||||
# include <qse/si/sio.h>
|
||||
# include <qse/cmn/path.h>
|
||||
# define HTTPD_DBGOUT0(fmt) qse_putmbsf("%06d %-20hs " fmt, (int)__LINE__, qse_mbsbasename(__FILE__))
|
||||
# define HTTPD_DBGOUT1(fmt,a1) qse_putmbsf("%06d %-20hs " fmt, (int)__LINE__, qse_mbsbasename(__FILE__), (a1))
|
||||
# define HTTPD_DBGOUT2(fmt,a1,a2) qse_putmbsf("%06d %-20hs " fmt, (int)__LINE__, qse_mbsbasename(__FILE__), (a1), (a2))
|
||||
# define HTTPD_DBGOUT3(fmt,a1,a2,a3) qse_putmbsf("%06d %-20hs " fmt, (int)__LINE__, qse_mbsbasename(__FILE__), (a1), (a2), (a3))
|
||||
# define HTTPD_DBGOUT4(fmt,a1,a2,a3,a4) qse_putmbsf("%06d %-20hs " fmt, (int)__LINE__, qse_mbsbasename(__FILE__), (a1), (a2), (a3), (a4))
|
||||
# define HTTPD_DBGOUT5(fmt,a1,a2,a3,a4,a5) qse_putmbsf("%06d %-20hs " fmt, (int)__LINE__, qse_mbsbasename(__FILE__), (a1), (a2), (a3), (a4), (a5))
|
||||
#else
|
||||
# define HTTPD_DBGOUT0(fmt)
|
||||
# define HTTPD_DBGOUT1(fmt,a1)
|
||||
# define HTTPD_DBGOUT2(fmt,a1,a2)
|
||||
# define HTTPD_DBGOUT3(fmt,a1,a2,a3)
|
||||
# define HTTPD_DBGOUT4(fmt,a1,a2,a3,a4)
|
||||
# define HTTPD_DBGOUT5(fmt,a1,a2,a3,a4,a5)
|
||||
#endif
|
||||
|
||||
#define QSE_HTTPD_DEFAULT_PORT 80
|
||||
#define QSE_HTTPD_DEFAULT_SECURE_PORT 443
|
||||
|
||||
|
||||
struct qse_httpd_t
|
||||
{
|
||||
QSE_HTTPD_HDR;
|
||||
qse_httpd_errnum_t errnum;
|
||||
qse_httpd_ecb_t* ecb; /* event callbacks */
|
||||
qse_tmr_t* tmr;
|
||||
|
||||
struct
|
||||
{
|
||||
int trait;
|
||||
qse_ntime_t tmout; /* poll timeout */
|
||||
qse_ntime_t idle_limit;
|
||||
qse_cstr_t mod[2]; /* module prefix and postfix */
|
||||
qse_httpd_scb_t scb; /* system callbacks */
|
||||
qse_httpd_rcb_t rcb; /* request callbacks */
|
||||
} opt;
|
||||
|
||||
int stopreq: 1;
|
||||
int impedereq: 1;
|
||||
int dnsactive: 1;
|
||||
int ursactive: 1;
|
||||
|
||||
qse_mchar_t sname[128]; /* server name for the server header */
|
||||
qse_mchar_t gtbuf[10][64]; /* GMT time buffers */
|
||||
|
||||
qse_httpd_mod_t* modlist;
|
||||
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
qse_httpd_client_t* head;
|
||||
qse_httpd_client_t* tail;
|
||||
qse_size_t count;
|
||||
} list;
|
||||
|
||||
struct
|
||||
{
|
||||
qse_httpd_client_t* head;
|
||||
qse_httpd_client_t* tail;
|
||||
} tasked;
|
||||
|
||||
qse_httpd_client_t* bad;
|
||||
} client;
|
||||
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
qse_httpd_server_t* head;
|
||||
qse_httpd_server_t* tail;
|
||||
} list;
|
||||
qse_size_t navail;
|
||||
qse_size_t nactive;
|
||||
} server;
|
||||
|
||||
void* mux;
|
||||
qse_httpd_dns_t dns;
|
||||
qse_httpd_urs_t urs;
|
||||
};
|
||||
|
||||
/* qse_httpd_real_task_t is a private type to hide some private fields
|
||||
* from being exposed by qse_httpd_task_t.
|
||||
*/
|
||||
typedef struct qse_httpd_real_task_t qse_httpd_real_task_t;
|
||||
|
||||
struct qse_httpd_real_task_t
|
||||
{
|
||||
qse_httpd_task_t core;
|
||||
qse_httpd_real_task_t* prev;
|
||||
qse_httpd_real_task_t* next;
|
||||
};
|
||||
|
||||
#define MAX_SEND_SIZE (4096 * 4)
|
||||
#define MAX_RECV_SIZE (4096 * 2)
|
||||
|
||||
#define MAX_NWAD_TEXT_SIZE 96
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern qse_http_version_t qse_http_v11;
|
||||
|
||||
int qse_httpd_init (
|
||||
qse_httpd_t* httpd,
|
||||
qse_mmgr_t* mmgr
|
||||
);
|
||||
|
||||
void qse_httpd_fini (
|
||||
qse_httpd_t* httpd
|
||||
);
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entask_status (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred,
|
||||
int code,
|
||||
void* extra,
|
||||
qse_http_method_t method,
|
||||
const qse_http_version_t* version,
|
||||
int keepalive
|
||||
);
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entask_nomod (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* pred,
|
||||
qse_http_method_t method,
|
||||
const qse_http_version_t* version,
|
||||
int keepalive
|
||||
);
|
||||
|
||||
int qse_httpd_activatetasktrigger (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* task
|
||||
);
|
||||
|
||||
int qse_httpd_inactivatetasktrigger (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
qse_httpd_task_t* task
|
||||
);
|
||||
|
||||
int qse_httpd_insert_timer_event (
|
||||
qse_httpd_t* httpd,
|
||||
const qse_tmr_event_t* event,
|
||||
qse_tmr_index_t* index
|
||||
);
|
||||
|
||||
void qse_httpd_remove_timer_event (
|
||||
qse_httpd_t* httpd,
|
||||
qse_tmr_index_t index
|
||||
);
|
||||
|
||||
qse_httpd_peer_t* qse_httpd_cacheproxypeer (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
qse_httpd_peer_t* tmpl
|
||||
);
|
||||
|
||||
qse_httpd_peer_t* qse_httpd_decacheproxypeer (
|
||||
qse_httpd_t* httpd,
|
||||
qse_httpd_client_t* client,
|
||||
const qse_nwad_t* nwad,
|
||||
const qse_nwad_t* local,
|
||||
int secure
|
||||
);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
586
lib/http/upxd.c
Normal file
586
lib/http/upxd.c
Normal file
@ -0,0 +1,586 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "upxd.h"
|
||||
#include <qse/cmn/str.h>
|
||||
|
||||
static void disable_all_servers (qse_upxd_t* upxd);
|
||||
static void free_all_servers (qse_upxd_t* upxd);
|
||||
static qse_upxd_server_session_t* find_server_session (
|
||||
qse_upxd_t* upxd, qse_upxd_server_t* server, qse_nwad_t* from);
|
||||
static void release_session (
|
||||
qse_upxd_t* upxd, qse_upxd_server_session_t* session);
|
||||
|
||||
|
||||
qse_upxd_t* qse_upxd_open (qse_mmgr_t* mmgr, qse_size_t xtnsize)
|
||||
{
|
||||
qse_upxd_t* upxd;
|
||||
|
||||
upxd = (qse_upxd_t*) QSE_MMGR_ALLOC (
|
||||
mmgr, QSE_SIZEOF(*upxd) + xtnsize
|
||||
);
|
||||
if (upxd == QSE_NULL) return QSE_NULL;
|
||||
|
||||
if (qse_upxd_init (upxd, mmgr) <= -1)
|
||||
{
|
||||
QSE_MMGR_FREE (mmgr, upxd);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
return upxd;
|
||||
}
|
||||
|
||||
void qse_upxd_close (qse_upxd_t* upxd)
|
||||
{
|
||||
qse_upxd_fini (upxd);
|
||||
QSE_MMGR_FREE (upxd->mmgr, upxd);
|
||||
}
|
||||
|
||||
int qse_upxd_init (qse_upxd_t* upxd, qse_mmgr_t* mmgr)
|
||||
{
|
||||
QSE_MEMSET (upxd, 0, QSE_SIZEOF(*upxd));
|
||||
upxd->mmgr = mmgr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qse_upxd_fini (qse_upxd_t* upxd)
|
||||
{
|
||||
if (upxd->server.nactive > 0) disable_all_servers (upxd);
|
||||
|
||||
if (upxd->mux)
|
||||
{
|
||||
upxd->cbs->mux.close (upxd, upxd->mux);
|
||||
upxd->mux = QSE_NULL;
|
||||
}
|
||||
|
||||
free_all_servers (upxd);
|
||||
}
|
||||
|
||||
qse_mmgr_t* qse_upxd_getmmgr (qse_upxd_t* upxd)
|
||||
{
|
||||
return upxd->mmgr;
|
||||
}
|
||||
|
||||
void* qse_upxd_getxtn (qse_upxd_t* upxd)
|
||||
{
|
||||
return QSE_XTN (upxd);
|
||||
}
|
||||
|
||||
qse_upxd_errnum_t qse_upxd_geterrnum (qse_upxd_t* upxd)
|
||||
{
|
||||
return upxd->errnum;
|
||||
}
|
||||
|
||||
void qse_upxd_seterrnum (qse_upxd_t* upxd, qse_upxd_errnum_t errnum)
|
||||
{
|
||||
upxd->errnum = errnum;
|
||||
}
|
||||
|
||||
QSE_INLINE void* qse_upxd_allocmem (qse_upxd_t* upxd, qse_size_t size)
|
||||
{
|
||||
void* ptr = QSE_MMGR_ALLOC (upxd->mmgr, size);
|
||||
if (ptr == QSE_NULL) upxd->errnum = QSE_UPXD_ENOMEM;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
QSE_INLINE void* qse_upxd_reallocmem (
|
||||
qse_upxd_t* upxd, void* ptr, qse_size_t size)
|
||||
{
|
||||
void* nptr = QSE_MMGR_REALLOC (upxd->mmgr, ptr, size);
|
||||
if (nptr == QSE_NULL) upxd->errnum = QSE_UPXD_ENOMEM;
|
||||
return nptr;
|
||||
}
|
||||
|
||||
QSE_INLINE void qse_upxd_freemem (qse_upxd_t* upxd, void* ptr)
|
||||
{
|
||||
QSE_MMGR_FREE (upxd->mmgr, ptr);
|
||||
}
|
||||
|
||||
|
||||
static int perform_session_task (
|
||||
qse_upxd_t* upxd, void* mux, qse_upxd_hnd_t handle, void* cbarg)
|
||||
{
|
||||
qse_upxd_server_session_t* session;
|
||||
qse_upxd_server_t* server;
|
||||
qse_ssize_t n;
|
||||
|
||||
session = (qse_upxd_server_session_t*)cbarg;
|
||||
server = session->inner.server;
|
||||
|
||||
qse_gettime (&session->modified);
|
||||
|
||||
/* this handler should set the 'from' field of server->scok */
|
||||
n = upxd->cbs->sock.recv (
|
||||
upxd, &session->peer, upxd->rbuf, QSE_SIZEOF(upxd->rbuf));
|
||||
if (n <= -1)
|
||||
{
|
||||
upxd->cbs->session.error (upxd, &session->inner);
|
||||
release_session (upxd, session);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TODO: inspect if session->inner.to matches session->sock.from.
|
||||
drop it if they don't match if a certain option (QSE_UPXD_STRICT)
|
||||
is set??? */
|
||||
|
||||
/* send the peer's packet back to the client */
|
||||
server->local.to = session->inner.client;
|
||||
n = upxd->cbs->sock.send (upxd, &server->local, upxd->rbuf, n);
|
||||
if (n <= -1)
|
||||
{
|
||||
upxd->cbs->session.error (upxd, &session->inner);
|
||||
release_session (upxd, session);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int perform_server_task (
|
||||
qse_upxd_t* upxd, void* mux, qse_upxd_hnd_t handle, void* cbarg)
|
||||
{
|
||||
qse_upxd_server_t* server;
|
||||
qse_upxd_server_session_t* session;
|
||||
qse_ssize_t n;
|
||||
|
||||
server = (qse_upxd_server_t*)cbarg;
|
||||
|
||||
/* this handler should set the 'from' field of server->scok */
|
||||
n = upxd->cbs->sock.recv (
|
||||
upxd, &server->local, upxd->rbuf, QSE_SIZEOF(upxd->rbuf));
|
||||
if (n <= -1) return -1;
|
||||
|
||||
/* get the existing session or create a new session based on
|
||||
* server->local->from */
|
||||
session = find_server_session (upxd, server, &server->local.from);
|
||||
if (session == QSE_NULL)
|
||||
{
|
||||
qse_upxd_session_t interim;
|
||||
QSE_MEMSET (&interim, 0, QSE_SIZEOF(interim));
|
||||
interim.client = server->local.from;
|
||||
upxd->cbs->session.error (upxd, &interim);
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = upxd->cbs->sock.send (upxd, &session->peer, upxd->rbuf, n);
|
||||
if (n <= -1)
|
||||
{
|
||||
upxd->cbs->session.error (upxd, &session->inner);
|
||||
release_session (upxd, session);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static qse_upxd_server_session_t* find_server_session (
|
||||
qse_upxd_t* upxd, qse_upxd_server_t* server, qse_nwad_t* from)
|
||||
{
|
||||
qse_upxd_server_session_t* session;
|
||||
|
||||
/* TODO: make it indexable or hashable with 'from'
|
||||
* don't perform linear search */
|
||||
/* find an existing session made for the source address 'from' */
|
||||
for (session = server->session.list; session; session = session->next)
|
||||
{
|
||||
if (QSE_MEMCMP (&session->inner.client, from, QSE_SIZEOF(*from)) == 0)
|
||||
{
|
||||
qse_gettime (&session->modified);
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
||||
/* there is no session found for the source address 'from'.
|
||||
* let's create a new session. */
|
||||
session = qse_upxd_allocmem (upxd, QSE_SIZEOF(*session));
|
||||
if (session == QSE_NULL) return QSE_NULL;
|
||||
|
||||
QSE_MEMSET (session, 0, QSE_SIZEOF(*session));
|
||||
|
||||
if (qse_gettime (&session->created) <= -1)
|
||||
{
|
||||
qse_upxd_freemem (upxd, session);
|
||||
upxd->errnum = QSE_UPXD_ESYSERR;
|
||||
return QSE_NULL;
|
||||
}
|
||||
session->modified = session->created;
|
||||
|
||||
session->inner.server = server;
|
||||
session->inner.client = *from;
|
||||
|
||||
/* set the default dormancy */
|
||||
session->inner.config.dormancy.sec = QSE_UPXD_SESSION_DORMANCY;
|
||||
session->inner.config.dormancy.nsec = 0;
|
||||
|
||||
/* call the configurationc callback for configuration data */
|
||||
if (upxd->cbs->session.config (upxd, &session->inner) <= -1)
|
||||
{
|
||||
qse_upxd_freemem (upxd, session);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
/* set up the peer socket with the configuration data */
|
||||
session->peer.bind = session->inner.config.bind;
|
||||
session->peer.to = session->inner.config.peer;
|
||||
if (session->inner.config.dev[0] != QSE_T('\0'))
|
||||
session->peer.dev = session->inner.config.dev;
|
||||
|
||||
if (upxd->cbs->sock.open (upxd, &session->peer) <= -1)
|
||||
{
|
||||
qse_upxd_freemem (upxd, session);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
if (upxd->cbs->mux.addhnd (
|
||||
upxd, upxd->mux, session->peer.handle,
|
||||
perform_session_task, session) <= -1)
|
||||
{
|
||||
upxd->cbs->sock.close (upxd, &session->peer);
|
||||
qse_upxd_freemem (upxd, session);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
/* insert the session into the head of the session list */
|
||||
if (server->session.list)
|
||||
server->session.list->prev = session;
|
||||
session->next = server->session.list;
|
||||
server->session.list = session;
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
static void release_session (
|
||||
qse_upxd_t* upxd, qse_upxd_server_session_t* session)
|
||||
{
|
||||
qse_upxd_server_t* server;
|
||||
|
||||
server = session->inner.server;
|
||||
QSE_ASSERT (server != QSE_NULL);
|
||||
|
||||
upxd->cbs->mux.delhnd (upxd, upxd->mux, session->peer.handle);
|
||||
upxd->cbs->sock.close (upxd, &session->peer);
|
||||
|
||||
/* remove the session from the session list */
|
||||
if (session->next) session->next->prev = session->prev;
|
||||
if (session->prev) session->prev->next = session->next;
|
||||
else server->session.list = session->next;
|
||||
|
||||
/* destroy the session */
|
||||
qse_upxd_freemem (upxd, session);
|
||||
}
|
||||
|
||||
static int enable_server (qse_upxd_t* upxd, qse_upxd_server_t* server)
|
||||
{
|
||||
QSE_ASSERT (upxd->cbs != QSE_NULL);
|
||||
QSE_ASSERT (!(server->flags & QSE_UPXD_SERVER_ENABLED));
|
||||
|
||||
if (upxd->cbs->sock.open (upxd, &server->local) <= -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (upxd->cbs->mux.addhnd (
|
||||
upxd, upxd->mux, server->local.handle,
|
||||
perform_server_task, server) <= -1)
|
||||
{
|
||||
upxd->cbs->sock.close (upxd, &server->local);
|
||||
return -1;
|
||||
}
|
||||
|
||||
server->flags |= QSE_UPXD_SERVER_ENABLED;
|
||||
upxd->server.nactive++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void disable_server (qse_upxd_t* upxd, qse_upxd_server_t* server)
|
||||
{
|
||||
qse_upxd_server_session_t* session;
|
||||
|
||||
QSE_ASSERT (upxd->cbs != QSE_NULL);
|
||||
QSE_ASSERT (server->flags & QSE_UPXD_SERVER_ENABLED);
|
||||
|
||||
session = server->session.list;
|
||||
while (session)
|
||||
{
|
||||
qse_upxd_server_session_t* next = session->next;
|
||||
release_session (upxd, session);
|
||||
session = next;
|
||||
}
|
||||
|
||||
upxd->cbs->mux.delhnd (upxd, upxd->mux, server->local.handle);
|
||||
upxd->cbs->sock.close (upxd, &server->local);
|
||||
|
||||
server->flags &= ~QSE_UPXD_SERVER_ENABLED;
|
||||
upxd->server.nactive--;
|
||||
}
|
||||
|
||||
static void enable_all_servers (qse_upxd_t* upxd)
|
||||
{
|
||||
qse_upxd_server_t* server;
|
||||
|
||||
for (server = upxd->server.list; server; server = server->next)
|
||||
{
|
||||
if (!(server->flags & QSE_UPXD_SERVER_ENABLED))
|
||||
{
|
||||
enable_server (upxd, server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void disable_all_servers (qse_upxd_t* upxd)
|
||||
{
|
||||
qse_upxd_server_t* server;
|
||||
|
||||
server = upxd->server.list;
|
||||
while (server)
|
||||
{
|
||||
if (server->flags & QSE_UPXD_SERVER_ENABLED)
|
||||
disable_server (upxd, server);
|
||||
|
||||
server = server->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void free_all_servers (qse_upxd_t* upxd)
|
||||
{
|
||||
qse_upxd_server_t* server;
|
||||
qse_upxd_server_t* next;
|
||||
|
||||
server = upxd->server.list;
|
||||
while (server)
|
||||
{
|
||||
next = server->next;
|
||||
QSE_MMGR_FREE (upxd->mmgr, server);
|
||||
server = next;
|
||||
}
|
||||
upxd->server.list = QSE_NULL;
|
||||
}
|
||||
|
||||
qse_upxd_server_t* qse_upxd_addserver (
|
||||
qse_upxd_t* upxd, const qse_nwad_t* nwad, const qse_char_t* dev)
|
||||
{
|
||||
qse_upxd_server_t* server;
|
||||
|
||||
if (dev && qse_strlen(dev) >= QSE_COUNTOF(server->dev))
|
||||
{
|
||||
upxd->errnum = QSE_UPXD_EINVAL;
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
server = QSE_MMGR_ALLOC (upxd->mmgr, QSE_SIZEOF(*server));
|
||||
if (server == QSE_NULL)
|
||||
{
|
||||
upxd->errnum = QSE_UPXD_ENOMEM;
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
QSE_MEMSET (server, 0, QSE_SIZEOF(*server));
|
||||
if (dev)
|
||||
{
|
||||
qse_strxcpy (server->dev, QSE_COUNTOF(server->dev), dev);
|
||||
server->local.dev = server->dev;
|
||||
}
|
||||
server->local.bind = *nwad;
|
||||
|
||||
/* chain it to the head of the list */
|
||||
if (upxd->server.list)
|
||||
upxd->server.list->prev = server;
|
||||
server->next = upxd->server.list;
|
||||
upxd->server.list = server;
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
void qse_upxd_delserver (
|
||||
qse_upxd_t* upxd, qse_upxd_server_t* server)
|
||||
{
|
||||
if (server->flags & QSE_UPXD_SERVER_ENABLED)
|
||||
disable_server (upxd, server);
|
||||
|
||||
/* unchain the session from the list */
|
||||
if (server->next) server->next->prev = server->prev;
|
||||
if (server->prev) server->prev->next = server->next;
|
||||
else upxd->server.list = server->next;
|
||||
}
|
||||
|
||||
void* qse_upxd_getserverctx (
|
||||
qse_upxd_t* upxd, qse_upxd_server_t* server)
|
||||
{
|
||||
return server->ctx;
|
||||
}
|
||||
|
||||
void qse_upxd_setserverctx (
|
||||
qse_upxd_t* upxd, qse_upxd_server_t* server, void* ctx)
|
||||
{
|
||||
server->ctx = ctx;
|
||||
}
|
||||
|
||||
qse_upxd_cbs_t* qse_upxd_getcbs (qse_upxd_t* upxd)
|
||||
{
|
||||
return upxd->cbs;
|
||||
}
|
||||
|
||||
void qse_upxd_setcbs (qse_upxd_t* upxd, qse_upxd_cbs_t* cbs)
|
||||
{
|
||||
upxd->cbs = cbs;
|
||||
}
|
||||
|
||||
static QSE_INLINE void purge_idle_sessions_in_server (
|
||||
qse_upxd_t* upxd, qse_upxd_server_t* server)
|
||||
{
|
||||
qse_upxd_server_session_t* session;
|
||||
qse_upxd_server_session_t* next;
|
||||
qse_ntime_t now;
|
||||
|
||||
qse_gettime (&now);
|
||||
|
||||
session = server->session.list;
|
||||
while (session)
|
||||
{
|
||||
next = session->next;
|
||||
|
||||
if (session->inner.config.dormancy.sec > 0 &&
|
||||
now.sec > session->modified.sec &&
|
||||
now.sec - session->modified.sec > session->inner.config.dormancy.sec)
|
||||
{
|
||||
release_session (upxd, session);
|
||||
}
|
||||
|
||||
session = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void purge_idle_sessions (qse_upxd_t* upxd)
|
||||
{
|
||||
qse_upxd_server_t* server;
|
||||
|
||||
for (server = upxd->server.list; server; server = server->next)
|
||||
{
|
||||
if (server->flags & QSE_UPXD_SERVER_ENABLED)
|
||||
{
|
||||
purge_idle_sessions_in_server (upxd, server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int qse_upxd_loop (qse_upxd_t* upxd, qse_ntime_t timeout)
|
||||
{
|
||||
int retv = -1;
|
||||
|
||||
QSE_ASSERTX (upxd->cbs != QSE_NULL,
|
||||
"Call qse_upxd_setcbs() before calling qse_upxd_loop()");
|
||||
|
||||
if (upxd->cbs == QSE_NULL)
|
||||
{
|
||||
upxd->errnum = QSE_UPXD_EINVAL;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (upxd->mux)
|
||||
{
|
||||
/* close the mutiplexer if it's open */
|
||||
upxd->cbs->mux.close (upxd, upxd->mux);
|
||||
upxd->mux = QSE_NULL;
|
||||
}
|
||||
|
||||
upxd->stopreq = 0;
|
||||
upxd->mux = upxd->cbs-> mux.open (upxd);
|
||||
if (upxd->mux == QSE_NULL) goto oops;
|
||||
|
||||
enable_all_servers (upxd);
|
||||
|
||||
while (!upxd->stopreq)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = upxd->cbs->mux.poll (upxd, upxd->mux, timeout);
|
||||
if (count <= -1)
|
||||
{
|
||||
/* TODO: anything? */
|
||||
}
|
||||
|
||||
purge_idle_sessions (upxd);
|
||||
enable_all_servers (upxd);
|
||||
}
|
||||
|
||||
retv = 0;
|
||||
|
||||
oops:
|
||||
if (upxd->server.nactive > 0) disable_all_servers (upxd);
|
||||
if (upxd->mux)
|
||||
{
|
||||
upxd->cbs->mux.close (upxd, upxd->mux);
|
||||
upxd->mux = QSE_NULL;
|
||||
}
|
||||
return retv;
|
||||
}
|
||||
|
||||
void qse_upxd_stop (qse_upxd_t* upxd)
|
||||
{
|
||||
upxd->stopreq = 1;
|
||||
}
|
||||
|
||||
int qse_upxd_enableserver (qse_upxd_t* upxd, qse_upxd_server_t* server)
|
||||
{
|
||||
if (server->flags & QSE_UPXD_SERVER_ENABLED)
|
||||
{
|
||||
upxd->errnum = QSE_UPXD_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return enable_server (upxd, server);
|
||||
}
|
||||
|
||||
int qse_upxd_disableserver (qse_upxd_t* upxd, qse_upxd_server_t* server)
|
||||
{
|
||||
if (!(server->flags & QSE_UPXD_SERVER_ENABLED))
|
||||
{
|
||||
upxd->errnum = QSE_UPXD_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
disable_server (upxd, server);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qse_upxd_poll (qse_upxd_t* upxd, qse_ntime_t timeout)
|
||||
{
|
||||
int ret;
|
||||
|
||||
QSE_ASSERTX (upxd->cbs != QSE_NULL,
|
||||
"Call qse_upxd_setcbs() before calling qse_upxd_loop()");
|
||||
|
||||
if (upxd->mux == QSE_NULL)
|
||||
{
|
||||
upxd->mux = upxd->cbs-> mux.open (upxd);
|
||||
if (upxd->mux == QSE_NULL) return -1;
|
||||
}
|
||||
|
||||
ret = upxd->cbs->mux.poll (upxd, upxd->mux, timeout);
|
||||
purge_idle_sessions (upxd);
|
||||
|
||||
return ret;
|
||||
}
|
107
lib/http/upxd.h
Normal file
107
lib/http/upxd.h
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _QSE_LIB_NET_UPXD_H_
|
||||
#define _QSE_LIB_NET_UPXD_H_
|
||||
|
||||
#include <qse/http/upxd.h>
|
||||
#include "../cmn/mem-prv.h"
|
||||
|
||||
typedef struct qse_upxd_server_session_t qse_upxd_server_session_t;
|
||||
|
||||
struct qse_upxd_server_t
|
||||
{
|
||||
qse_upxd_server_t* next;
|
||||
qse_upxd_server_t* prev;
|
||||
|
||||
#define QSE_UPXD_SERVER_ENABLED (1 << 0)
|
||||
int flags;
|
||||
|
||||
/* the socket can be bound to this interface.
|
||||
* sock->dev points to this buffer when necessary. */
|
||||
qse_char_t dev[QSE_UPXD_SESSION_DEV_LEN + 1];
|
||||
|
||||
/* list of sessions beloning to this server */
|
||||
struct
|
||||
{
|
||||
qse_upxd_server_session_t* list;
|
||||
qse_size_t count;
|
||||
} session;
|
||||
|
||||
qse_upxd_sock_t local;
|
||||
|
||||
/* user-defined context data that can be set
|
||||
* with qse_upxd_setserverctx() */
|
||||
void* ctx;
|
||||
};
|
||||
|
||||
struct qse_upxd_server_session_t
|
||||
{
|
||||
/* internal fields */
|
||||
qse_upxd_server_session_t* next;
|
||||
qse_upxd_server_session_t* prev;
|
||||
|
||||
/* timestamps for housekeeping */
|
||||
qse_ntime_t created;
|
||||
qse_ntime_t modified;
|
||||
|
||||
/* socket used to talk with a peer */
|
||||
qse_upxd_sock_t peer;
|
||||
|
||||
/* exposed to a caller via callbacks */
|
||||
qse_upxd_session_t inner;
|
||||
};
|
||||
|
||||
struct qse_upxd_t
|
||||
{
|
||||
qse_mmgr_t* mmgr;
|
||||
qse_upxd_errnum_t errnum;
|
||||
|
||||
int stopreq;
|
||||
qse_upxd_cbs_t* cbs;
|
||||
|
||||
struct
|
||||
{
|
||||
qse_upxd_server_t* list;
|
||||
qse_size_t nactive;
|
||||
} server;
|
||||
|
||||
void* mux;
|
||||
qse_uint8_t rbuf[65535];
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int qse_upxd_init (qse_upxd_t* upxd, qse_mmgr_t* mmgr);
|
||||
void qse_upxd_fini (qse_upxd_t* upxd);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user