diff --git a/qse/configure b/qse/configure index 50d04056..f19e69ce 100755 --- a/qse/configure +++ b/qse/configure @@ -16680,7 +16680,7 @@ QSE_PROJECT_AUTHOR="${PACKAGE_BUGREPORT}" QSE_PROJECT_URL="${PACKAGE_URL}" -ac_config_files="$ac_config_files Makefile README include/Makefile include/qse/Makefile include/qse/cmn/Makefile include/qse/awk/Makefile include/qse/cut/Makefile include/qse/sed/Makefile include/qse/stx/Makefile lib/Makefile lib/cmn/Makefile lib/awk/Makefile lib/cut/Makefile lib/sed/Makefile lib/stx/Makefile lib/http/Makefile cmd/Makefile cmd/awk/Makefile cmd/cut/Makefile cmd/sed/Makefile cmd/stx/Makefile samples/Makefile samples/cmn/Makefile samples/awk/Makefile samples/cut/Makefile samples/sed/Makefile samples/http/Makefile regress/Makefile regress/awk/Makefile regress/sed/Makefile doc/Makefile doc/page/Makefile doc/Doxyfile" +ac_config_files="$ac_config_files Makefile README include/Makefile include/qse/Makefile include/qse/cmn/Makefile include/qse/awk/Makefile include/qse/cut/Makefile include/qse/sed/Makefile include/qse/stx/Makefile include/qse/net/Makefile lib/Makefile lib/cmn/Makefile lib/awk/Makefile lib/cut/Makefile lib/sed/Makefile lib/stx/Makefile lib/net/Makefile cmd/Makefile cmd/awk/Makefile cmd/cut/Makefile cmd/sed/Makefile cmd/stx/Makefile samples/Makefile samples/cmn/Makefile samples/awk/Makefile samples/cut/Makefile samples/sed/Makefile samples/net/Makefile regress/Makefile regress/awk/Makefile regress/sed/Makefile doc/Makefile doc/page/Makefile doc/Doxyfile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -17780,13 +17780,14 @@ do "include/qse/cut/Makefile") CONFIG_FILES="$CONFIG_FILES include/qse/cut/Makefile" ;; "include/qse/sed/Makefile") CONFIG_FILES="$CONFIG_FILES include/qse/sed/Makefile" ;; "include/qse/stx/Makefile") CONFIG_FILES="$CONFIG_FILES include/qse/stx/Makefile" ;; + "include/qse/net/Makefile") CONFIG_FILES="$CONFIG_FILES include/qse/net/Makefile" ;; "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; "lib/cmn/Makefile") CONFIG_FILES="$CONFIG_FILES lib/cmn/Makefile" ;; "lib/awk/Makefile") CONFIG_FILES="$CONFIG_FILES lib/awk/Makefile" ;; "lib/cut/Makefile") CONFIG_FILES="$CONFIG_FILES lib/cut/Makefile" ;; "lib/sed/Makefile") CONFIG_FILES="$CONFIG_FILES lib/sed/Makefile" ;; "lib/stx/Makefile") CONFIG_FILES="$CONFIG_FILES lib/stx/Makefile" ;; - "lib/http/Makefile") CONFIG_FILES="$CONFIG_FILES lib/http/Makefile" ;; + "lib/net/Makefile") CONFIG_FILES="$CONFIG_FILES lib/net/Makefile" ;; "cmd/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/Makefile" ;; "cmd/awk/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/awk/Makefile" ;; "cmd/cut/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/cut/Makefile" ;; @@ -17797,7 +17798,7 @@ do "samples/awk/Makefile") CONFIG_FILES="$CONFIG_FILES samples/awk/Makefile" ;; "samples/cut/Makefile") CONFIG_FILES="$CONFIG_FILES samples/cut/Makefile" ;; "samples/sed/Makefile") CONFIG_FILES="$CONFIG_FILES samples/sed/Makefile" ;; - "samples/http/Makefile") CONFIG_FILES="$CONFIG_FILES samples/http/Makefile" ;; + "samples/net/Makefile") CONFIG_FILES="$CONFIG_FILES samples/net/Makefile" ;; "regress/Makefile") CONFIG_FILES="$CONFIG_FILES regress/Makefile" ;; "regress/awk/Makefile") CONFIG_FILES="$CONFIG_FILES regress/awk/Makefile" ;; "regress/sed/Makefile") CONFIG_FILES="$CONFIG_FILES regress/sed/Makefile" ;; diff --git a/qse/configure.ac b/qse/configure.ac index 22b2b8d9..d6814580 100644 --- a/qse/configure.ac +++ b/qse/configure.ac @@ -236,13 +236,14 @@ AC_CONFIG_FILES([ include/qse/cut/Makefile include/qse/sed/Makefile include/qse/stx/Makefile + include/qse/net/Makefile lib/Makefile lib/cmn/Makefile lib/awk/Makefile lib/cut/Makefile lib/sed/Makefile lib/stx/Makefile - lib/http/Makefile + lib/net/Makefile cmd/Makefile cmd/awk/Makefile cmd/cut/Makefile @@ -253,7 +254,7 @@ AC_CONFIG_FILES([ samples/awk/Makefile samples/cut/Makefile samples/sed/Makefile - samples/http/Makefile + samples/net/Makefile regress/Makefile regress/awk/Makefile regress/sed/Makefile diff --git a/qse/include/qse/Makefile.am b/qse/include/qse/Makefile.am index bd43512c..50742d31 100644 --- a/qse/include/qse/Makefile.am +++ b/qse/include/qse/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = cmn awk cut sed stx +SUBDIRS = cmn awk cut sed stx net pkgincludedir = $(includedir)/qse diff --git a/qse/include/qse/Makefile.in b/qse/include/qse/Makefile.in index f8805abd..da301963 100644 --- a/qse/include/qse/Makefile.in +++ b/qse/include/qse/Makefile.in @@ -254,7 +254,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -SUBDIRS = cmn awk cut sed stx +SUBDIRS = cmn awk cut sed stx net pkginclude_HEADERS = conf_msw.h conf_os2.h conf_dos.h conf_vms.h \ types.h macros.h pack1.h unpack.h $(am__append_1) all: config.h diff --git a/qse/include/qse/http/Makefile.am b/qse/include/qse/http/Makefile.am deleted file mode 100644 index 422a1e67..00000000 --- a/qse/include/qse/http/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -pkgincludedir= $(includedir)/qse/http -pkginclude_HEADERS = http.h - - diff --git a/qse/include/qse/http/http.h b/qse/include/qse/http/http.h deleted file mode 100644 index 07bcdf00..00000000 --- a/qse/include/qse/http/http.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * $Id: http.h 223 2008-06-26 06:44:41Z baconevi $ - * - Copyright 2006-2011 Chung, Hyung-Hwan. - This file is part of QSE. - - QSE is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - QSE is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with QSE. If not, see . - */ - -#ifndef _QSE_HTTP_HTTP_H_ -#define _QSE_HTTP_HTTP_H_ - -#include - -typedef struct qse_http_t qse_http_t; - -enum qse_http_errnum_t -{ - QSE_HTTP_ENOERR, - QSE_HTTP_ENOMEM, - QSE_HTTP_EBADRE, - QSE_HTTP_EBADHDR, - QSE_HTTP_EREQCBS -}; - -typedef enum qse_http_errnum_t qse_http_errnum_t; - -enum qse_http_option_t -{ - QSE_HTTP_LEADINGEMPTYLINES = (1 << 0) -}; - -typedef enum qse_http_option_t qse_http_option_t; - -typedef struct qse_http_recbs_t qse_http_recbs_t; - -struct qse_http_recbs_t -{ - int (*request) (qse_http_t* http, qse_htre_t* req); - int (*response) (qse_http_t* http, qse_htre_t* res); - int (*expect_continue) (qse_http_t* http, qse_htre_t* req); -}; - -struct qse_http_t -{ - QSE_DEFINE_COMMON_FIELDS (http) - qse_http_errnum_t errnum; - int option; - - qse_http_recbs_t recbs; - - struct - { - struct - { - int crlf; /* crlf status */ - qse_size_t plen; /* raw request length excluding crlf */ - qse_size_t need; /* number of octets needed for contents */ - - struct - { - qse_size_t len; - qse_size_t count; - int phase; - } chunk; - } s; /* state */ - - - /* buffers needed to for processing a request */ - struct - { - qse_htob_t raw; /* buffer to hold raw octets */ - qse_htob_t tra; /* buffer for handling trailers */ - qse_htob_t pen; /* buffer for raw octets during pending period */ - } b; - - /* points to the head of the combined header list */ - void* chl; - } fed; - - enum - { - QSE_HTTP_RETYPE_Q, - QSE_HTTP_RETYPE_S - } retype; - - qse_htre_t re; -}; - -#ifdef __cplusplus -extern "C" { -#endif - -QSE_DEFINE_COMMON_FUNCTIONS (http) - -/** - * The qse_http_open() function creates a http processor. - */ -qse_http_t* qse_http_open ( - qse_mmgr_t* mmgr, /**< memory manager */ - qse_size_t xtnsize /**< extension size in bytes */ -); - -/** - * The qse_http_close() function destroys a http processor. - */ -void qse_http_close ( - qse_http_t* http -); - -qse_http_t* qse_http_init ( - qse_http_t* http, - qse_mmgr_t* mmgr -); - -void qse_http_fini ( - qse_http_t* http -); - -void qse_http_clear ( - qse_http_t* http -); - -int qse_http_getoption ( - qse_http_t* http -); - -void qse_http_setoption ( - qse_http_t* http, - int opts -); - -const qse_http_recbs_t* qse_http_getrecbs ( - qse_http_t* http -); - -void qse_http_setrecbs ( - qse_http_t* http, - const qse_http_recbs_t* recbs -); - -/** - * The qse_http_feed() function accepts http request octets and invokes a - * callback function if it has processed a proper http request. - */ -int qse_http_feed ( - qse_http_t* http, /**< http */ - const qse_htoc_t* req, /**< request octets */ - qse_size_t len /**< number of octets */ -); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/qse/include/qse/net/Makefile.am b/qse/include/qse/net/Makefile.am new file mode 100644 index 00000000..2a6b3d7d --- /dev/null +++ b/qse/include/qse/net/Makefile.am @@ -0,0 +1,4 @@ +pkgincludedir= $(includedir)/qse/net +pkginclude_HEADERS = htre.h htrd.h http.h + + diff --git a/qse/include/qse/http/Makefile.in b/qse/include/qse/net/Makefile.in similarity index 98% rename from qse/include/qse/http/Makefile.in rename to qse/include/qse/net/Makefile.in index d583894a..f31c785c 100644 --- a/qse/include/qse/http/Makefile.in +++ b/qse/include/qse/net/Makefile.in @@ -33,7 +33,7 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -subdir = include/qse/http +subdir = include/qse/net DIST_COMMON = $(pkginclude_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -75,7 +75,7 @@ HEADERS = $(pkginclude_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -pkgincludedir = $(includedir)/qse/http +pkgincludedir = $(includedir)/qse/net ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ @@ -213,7 +213,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -pkginclude_HEADERS = http.h +pkginclude_HEADERS = htre.h htrd.h http.h all: all-am .SUFFIXES: @@ -226,9 +226,9 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/qse/http/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/qse/net/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign include/qse/http/Makefile + $(AUTOMAKE) --foreign include/qse/net/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff --git a/qse/include/qse/net/htrd.h b/qse/include/qse/net/htrd.h new file mode 100644 index 00000000..22bd7a07 --- /dev/null +++ b/qse/include/qse/net/htrd.h @@ -0,0 +1,179 @@ +/* + * $Id: htrd.h 223 2008-06-26 06:44:41Z baconevi $ + * + Copyright 2006-2011 Chung, Hyung-Hwan. + This file is part of QSE. + + QSE is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + QSE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with QSE. If not, see . + */ + +#ifndef _QSE_NET_HTRD_H_ +#define _QSE_NET_HTRD_H_ + +#include +#include + +typedef struct qse_htrd_t qse_htrd_t; + +enum qse_htrd_errnum_t +{ + QSE_HTRD_ENOERR, + QSE_HTRD_ENOMEM, + + QSE_HTRD_EDISCON, + QSE_HTRD_EREADER, + + QSE_HTRD_EBADRE, + QSE_HTRD_EBADHDR, + QSE_HTRD_EREQCBS +}; + +typedef enum qse_htrd_errnum_t qse_htrd_errnum_t; + +enum qse_htrd_option_t +{ + QSE_HTRD_LEADINGEMPTYLINES = (1 << 0) +}; + +typedef enum qse_htrd_option_t qse_htrd_option_t; + +typedef struct qse_htrd_recbs_t qse_htrd_recbs_t; + +struct qse_htrd_recbs_t +{ + /* octet reader and writer */ + qse_ssize_t (*reader) (qse_htrd_t* htrd, qse_htoc_t* buf, qse_size_t len); + + int (*request) (qse_htrd_t* htrd, qse_htre_t* req); + int (*response) (qse_htrd_t* htrd, qse_htre_t* res); + int (*expect_continue) (qse_htrd_t* htrd, qse_htre_t* req); +}; + +struct qse_htrd_t +{ + QSE_DEFINE_COMMON_FIELDS (htrd) + qse_htrd_errnum_t errnum; + int option; + + qse_htrd_recbs_t recbs; + + struct + { + struct + { + int crlf; /* crlf status */ + qse_size_t plen; /* raw request length excluding crlf */ + qse_size_t need; /* number of octets needed for contents */ + + struct + { + qse_size_t len; + qse_size_t count; + int phase; + } chunk; + } s; /* state */ + + + /* buffers needed to for processing a request */ + struct + { + qse_htob_t raw; /* buffer to hold raw octets */ + qse_htob_t tra; /* buffer for handling trailers */ + } b; + + /* points to the head of the combined header list */ + void* chl; + } fed; + + enum + { + QSE_HTRD_RETYPE_Q, + QSE_HTRD_RETYPE_S + } retype; + qse_htre_t re; + + qse_htoc_t rbuf[4096]; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +QSE_DEFINE_COMMON_FUNCTIONS (htrd) + +/** + * The qse_htrd_open() function creates a htrd processor. + */ +qse_htrd_t* qse_htrd_open ( + qse_mmgr_t* mmgr, /**< memory manager */ + qse_size_t xtnsize /**< extension size in bytes */ +); + +/** + * The qse_htrd_close() function destroys a htrd processor. + */ +void qse_htrd_close ( + qse_htrd_t* htrd +); + +qse_htrd_t* qse_htrd_init ( + qse_htrd_t* htrd, + qse_mmgr_t* mmgr +); + +void qse_htrd_fini ( + qse_htrd_t* htrd +); + +void qse_htrd_clear ( + qse_htrd_t* htrd +); + +int qse_htrd_getoption ( + qse_htrd_t* htrd +); + +void qse_htrd_setoption ( + qse_htrd_t* htrd, + int opts +); + +const qse_htrd_recbs_t* qse_htrd_getrecbs ( + qse_htrd_t* htrd +); + +void qse_htrd_setrecbs ( + qse_htrd_t* htrd, + const qse_htrd_recbs_t* recbs +); + +/** + * The qse_htrd_feed() function accepts htrd request octets and invokes a + * callback function if it has processed a proper htrd request. + */ +int qse_htrd_feed ( + qse_htrd_t* htrd, /**< htrd */ + const qse_htoc_t* req, /**< request octets */ + qse_size_t len /**< number of octets */ +); + +int qse_htrd_read ( + qse_htrd_t* htrd /**< htrd */ +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/qse/include/qse/http/htre.h b/qse/include/qse/net/htre.h similarity index 53% rename from qse/include/qse/http/htre.h rename to qse/include/qse/net/htre.h index 0af2d9c1..bc10baa9 100644 --- a/qse/include/qse/http/htre.h +++ b/qse/include/qse/net/htre.h @@ -18,30 +18,13 @@ License along with QSE. If not, see . */ -#ifndef _QSE_HTTP_HTRE_H_ -#define _QSE_HTTP_HTRE_H_ +#ifndef _QSE_NET_HTRE_H_ +#define _QSE_NET_HTRE_H_ -#include -#include +#include #include #include -/*typedef qse_byte_t qse_htoc_t;*/ -typedef qse_mchar_t qse_htoc_t; - -/* octet buffer */ -typedef qse_mbs_t qse_htob_t; - -/* octet string */ -typedef qse_mxstr_t qse_htos_t; - -typedef struct qse_htvr_t qse_htvr_t; -struct qse_htvr_t -{ - short major; - short minor; -}; - /* header and contents of request/response */ typedef struct qse_htre_t qse_htre_t; struct qse_htre_t @@ -49,34 +32,11 @@ struct qse_htre_t qse_mmgr_t* mmgr; /* version */ - qse_htvr_t version; + qse_http_version_t version; - union - { - struct - { - enum - { - QSE_HTTP_REQ_GET, - QSE_HTTP_REQ_HEAD, - QSE_HTTP_REQ_POST, - QSE_HTTP_REQ_PUT, - QSE_HTTP_REQ_DELETE, - QSE_HTTP_REQ_TRACE, - QSE_HTTP_REQ_OPTIONS, - QSE_HTTP_REQ_CONNECT - } method; - - qse_htos_t path; - /* qse_htos_t args; */ - } quest; - - struct - { - int code; - qse_htos_t message; - } sponse; - } re; + int qmethod_or_sstatus; + qse_htob_t qpath_or_smesg; + qse_htob_t qparamstr; /* special attributes derived from the header */ struct @@ -84,8 +44,6 @@ struct qse_htre_t int chunked; int content_length; int connection_close; - qse_htos_t content_type; - qse_htos_t host; int expect_continue; } attr; @@ -99,8 +57,27 @@ struct qse_htre_t int discard; }; -#define qse_htre_getversion(re) &((re)->version) +#define qse_htre_getversion(re) (&((re)->version)) +#define qse_htre_getmajorversion(re) ((re)->version.major) +#define qse_htre_getminorversion(re) ((re)->version.minor) #define qse_htre_setversion(re,v) QSE_BLOCK((re)->version = *(v);) + +#define qse_htre_getqmethod(re) ((re)->qmethod_or_sstatus) +#define qse_htre_setqmethod(re,v) QSE_BLOCK((re)->qmethod_or_sstatus=(v);) + +#define qse_htre_getsstatus(re) ((re)->qmethod_or_sstatus) +#define qse_htre_setsstatus(re,v) QSE_BLOCK((re)->qmethod_or_sstatus=(v);) + +#define qse_htre_setqpath(re,v) qse_htre_setbuf((re),&(re)->qpath_or_smesg,(v)) +#define qse_htre_setsmessage(re,v) qse_htre_setbuf((re),&(re)->qpath_or_smesg,(v)) + +#define qse_htre_getqpathptr(re) QSE_MBS_PTR(&(re)->qpath_or_smesg) +#define qse_htre_getqpathlen(re) QSE_MBS_LEN(&(re)->qpath_or_smesg) +#define qse_htre_getqparamsptr(re) QSE_MBS_PTR(&(re)->qparamstr) +#define qse_htre_getqparamslen(re) QSE_MBS_LEN(&(re)->qparamstr) +#define qse_htre_getsmessageptr(re) QSE_MBS_PTR(&(re)->qpath_or_smesg) +#define qse_htre_getsmessagelen(re) QSE_MBS_LEN(&(re)->qpath_or_smesg) + #define qse_htre_setdiscard(re,v) QSE_BLOCK((re)->discard = (v);) #ifdef __cplusplus @@ -120,6 +97,23 @@ void qse_htre_clear ( qse_htre_t* re ); +int qse_htre_setbuf ( + qse_htre_t* re, + qse_htob_t* buf, + const qse_htos_t* str +); + +void qse_htre_getbuf ( + qse_htre_t* re, + const qse_htob_t* buf, + qse_htos_t* str +); + +int qse_htre_setqparamstr ( + qse_htre_t* re, + const qse_htoc_t* str +); + #ifdef __cplusplus } #endif diff --git a/qse/include/qse/net/http.h b/qse/include/qse/net/http.h new file mode 100644 index 00000000..6bd49489 --- /dev/null +++ b/qse/include/qse/net/http.h @@ -0,0 +1,94 @@ +/* + * $Id: http.h 223 2008-06-26 06:44:41Z baconevi $ + * + Copyright 2006-2011 Chung, Hyung-Hwan. + This file is part of QSE. + + QSE is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + QSE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with QSE. If not, see . + */ + +#ifndef _QSE_NET_HTTP_H_ +#define _QSE_NET_HTTP_H_ + +#include +#include +#include +#include + +/*typedef qse_byte_t qse_htoc_t;*/ +typedef qse_mchar_t qse_htoc_t; + +/* octet buffer */ +typedef qse_mbs_t qse_htob_t; + +/* octet string */ +typedef qse_mxstr_t qse_htos_t; + +typedef struct qse_http_version_t qse_http_version_t; +struct qse_http_version_t +{ + short major; + short minor; +}; + +enum qse_http_method_t +{ + QSE_HTTP_GET, + QSE_HTTP_HEAD, + QSE_HTTP_POST, + QSE_HTTP_PUT, + QSE_HTTP_DELETE, + QSE_HTTP_TRACE, + QSE_HTTP_OPTIONS, + QSE_HTTP_CONNECT +}; + +typedef enum qse_http_method_t qse_http_method_t; + +typedef int (*qse_scanhttpparamstr_callback_t) ( + void* ctx, + const qse_mcstr_t* key, + const qse_mcstr_t* val +); + +#ifdef __cplusplus +extern "C" { +#endif + +const qse_htoc_t* qse_gethttpmethodname ( + qse_http_method_t type +); + +int qse_gethttpmethodtype ( + const qse_htoc_t* name, + qse_http_method_t* method +); + +int qse_gethttpmethodtypefromstr ( + const qse_htos_t* name, + qse_http_method_t* type +); + +int qse_scanhttpparamstr ( + const qse_htoc_t* paramstr, + qse_scanhttpparamstr_callback_t callback, + void* ctx +); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/qse/lib/Makefile.am b/qse/lib/Makefile.am index d0ce9da9..c64a3ea3 100644 --- a/qse/lib/Makefile.am +++ b/qse/lib/Makefile.am @@ -1,2 +1,2 @@ -SUBDIRS = cmn sed awk cut stx +SUBDIRS = cmn sed awk cut stx net DIST_SUBDIRS = $(SUBDIRS) diff --git a/qse/lib/Makefile.in b/qse/lib/Makefile.in index 5682a57c..4838d92c 100644 --- a/qse/lib/Makefile.in +++ b/qse/lib/Makefile.in @@ -225,7 +225,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -SUBDIRS = cmn sed awk cut stx +SUBDIRS = cmn sed awk cut stx net DIST_SUBDIRS = $(SUBDIRS) all: all-recursive diff --git a/qse/lib/cmn/str_dynm.c b/qse/lib/cmn/str_dynm.c index 7f56ea17..3c2110bd 100644 --- a/qse/lib/cmn/str_dynm.c +++ b/qse/lib/cmn/str_dynm.c @@ -1,5 +1,5 @@ /* - * $Id: str_dynm.c 497 2011-06-20 14:56:40Z hyunghwan.chung $ + * $Id: str_dynm.c 501 2011-07-05 15:45:00Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -249,7 +249,7 @@ qse_size_t qse_mbs_ncpy (qse_mbs_t* str, const qse_mchar_t* s, qse_size_t len) } str->val.len = qse_mbsncpy (str->val.ptr, s, len); - str->val.ptr[str->val.len] = QSE_MT('\0'); + /*str->val.ptr[str->val.len] = QSE_MT('\0'); -> mbsncpy does this*/ return str->val.len; } diff --git a/qse/lib/cmn/str_dynw.c b/qse/lib/cmn/str_dynw.c index 74052954..3c3a6f3c 100644 --- a/qse/lib/cmn/str_dynw.c +++ b/qse/lib/cmn/str_dynw.c @@ -1,5 +1,5 @@ /* - * $Id: str_dynw.c 497 2011-06-20 14:56:40Z hyunghwan.chung $ + * $Id: str_dynw.c 501 2011-07-05 15:45:00Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -249,7 +249,7 @@ qse_size_t qse_wcs_ncpy (qse_wcs_t* str, const qse_wchar_t* s, qse_size_t len) } str->val.len = qse_wcsncpy (str->val.ptr, s, len); - str->val.ptr[str->val.len] = QSE_WT('\0'); + /* str->val.ptr[str->val.len] = QSE_WT('\0'); -> wcsncpy does this */ return str->val.len; } diff --git a/qse/lib/http/Makefile.am b/qse/lib/http/Makefile.am deleted file mode 100644 index 7bd1aa65..00000000 --- a/qse/lib/http/Makefile.am +++ /dev/null @@ -1,14 +0,0 @@ -AUTOMAKE_OPTIONS = nostdinc - -AM_CPPFLAGS = \ - -I$(top_builddir)/include \ - -I$(top_srcdir)/include \ - -I$(includedir) - -lib_LTLIBRARIES = libqsehttp.la -libqsehttp_la_SOURCES = \ - htre.c \ - http.c - -libqsehttp_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir) -libqsehttp_la_LIBADD = -lqsecmn diff --git a/qse/lib/http/htre.c b/qse/lib/http/htre.c deleted file mode 100644 index f02898d0..00000000 --- a/qse/lib/http/htre.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * $Id$ - */ -#include -#include "../cmn/mem.h" - -qse_htre_t* qse_htre_init (qse_htre_t* re, qse_mmgr_t* mmgr) -{ - QSE_MEMSET (re, 0, QSE_SIZEOF(*re)); - re->mmgr = mmgr; - - if (qse_htb_init (&re->hdrtab, mmgr, 60, 70, 1, 1) == QSE_NULL) - { - return QSE_NULL; - } - - if (qse_mbs_init (&re->content, mmgr, 0) == QSE_NULL) - { - return QSE_NULL; - } - - return re; -} - -void qse_htre_fini (qse_htre_t* re) -{ - qse_mbs_fini (&re->content); - qse_htb_fini (&re->hdrtab); -} - -void qse_htre_clear (qse_htre_t* re) -{ - QSE_MEMSET (&re->version, 0, QSE_SIZEOF(re->version)); - QSE_MEMSET (&re->re, 0, QSE_SIZEOF(re->re)); - QSE_MEMSET (&re->attr, 0, QSE_SIZEOF(re->attr)); - - qse_htb_clear (&re->hdrtab); - qse_mbs_clear (&re->content); - - re->discard = 0; -} - -static QSE_INLINE int xdigit_to_num (qse_htoc_t c) -{ - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'A' && c <= 'Z') return c - 'A' + 10; - if (c >= 'a' && c <= 'z') return c - 'a' + 10; - return -1; -} - -int qse_htre_decodereqpath (qse_htre_t* re, int ) -{ - qse_htoc_t* p = re->re.quest.path.ptr; - qse_htoc_t* tmp = re->re.quest.path.ptr; - - while (*p != '\0') - { - if (*p == '%') - { - int q = xdigit_to_num(*(p+1)); - int w = xdigit_to_num(*(p+2)); - - if (q >= 0 && w >= 0) - { - int t = (q << 4) + w; - if (t == 0) - { - /* percent enconding contains a null character */ - return -1; - } - - *tmp++ = t; - p += 3; - } - else *tmp++ = *p++; - } - else if (*p == '?') - { -#if 0 - if (!http->re.re.quest.args.ptr) - { - /* ? must be explicit to be a argument instroducer. - * %3f is just a literal. */ - http->re.re.quest.path.len = tmp - http->re.re.quest.path.ptr; - *tmp++ = '\0'; - http->re.re.quest.args.ptr = tmp; - p++; - } - else *tmp++ = *p++; -#endif - } - else *tmp++ = *p++; - } - *tmp = '\0'; - - return 0; -} - - diff --git a/qse/lib/net/Makefile.am b/qse/lib/net/Makefile.am new file mode 100644 index 00000000..57a9cb92 --- /dev/null +++ b/qse/lib/net/Makefile.am @@ -0,0 +1,15 @@ +AUTOMAKE_OPTIONS = nostdinc + +AM_CPPFLAGS = \ + -I$(top_builddir)/include \ + -I$(top_srcdir)/include \ + -I$(includedir) + +lib_LTLIBRARIES = libqsenet.la +libqsenet_la_SOURCES = \ + http.c \ + htre.c \ + htrd.c + +libqsenet_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir) +libqsenet_la_LIBADD = -lqsecmn diff --git a/qse/lib/http/Makefile.in b/qse/lib/net/Makefile.in similarity index 95% rename from qse/lib/http/Makefile.in rename to qse/lib/net/Makefile.in index ef8bfebd..354797f0 100644 --- a/qse/lib/http/Makefile.in +++ b/qse/lib/net/Makefile.in @@ -34,7 +34,7 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -subdir = lib/http +subdir = lib/net DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ @@ -70,12 +70,12 @@ am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) -libqsehttp_la_DEPENDENCIES = -am_libqsehttp_la_OBJECTS = htre.lo http.lo -libqsehttp_la_OBJECTS = $(am_libqsehttp_la_OBJECTS) -libqsehttp_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ +libqsenet_la_DEPENDENCIES = +am_libqsenet_la_OBJECTS = http.lo htre.lo htrd.lo +libqsenet_la_OBJECTS = $(am_libqsenet_la_OBJECTS) +libqsenet_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libqsehttp_la_LDFLAGS) $(LDFLAGS) -o $@ + $(libqsenet_la_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = depcomp = $(SHELL) $(top_srcdir)/ac/depcomp am__depfiles_maybe = depfiles @@ -89,8 +89,8 @@ CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ -SOURCES = $(libqsehttp_la_SOURCES) -DIST_SOURCES = $(libqsehttp_la_SOURCES) +SOURCES = $(libqsenet_la_SOURCES) +DIST_SOURCES = $(libqsenet_la_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -237,13 +237,14 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/include \ -I$(includedir) -lib_LTLIBRARIES = libqsehttp.la -libqsehttp_la_SOURCES = \ +lib_LTLIBRARIES = libqsenet.la +libqsenet_la_SOURCES = \ + http.c \ htre.c \ - http.c + htrd.c -libqsehttp_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir) -libqsehttp_la_LIBADD = -lqsecmn +libqsenet_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir) +libqsenet_la_LIBADD = -lqsecmn all: all-am .SUFFIXES: @@ -257,9 +258,9 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/http/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/net/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign lib/http/Makefile + $(AUTOMAKE) --foreign lib/net/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -309,8 +310,8 @@ clean-libLTLIBRARIES: echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done -libqsehttp.la: $(libqsehttp_la_OBJECTS) $(libqsehttp_la_DEPENDENCIES) - $(libqsehttp_la_LINK) -rpath $(libdir) $(libqsehttp_la_OBJECTS) $(libqsehttp_la_LIBADD) $(LIBS) +libqsenet.la: $(libqsenet_la_OBJECTS) $(libqsenet_la_DEPENDENCIES) + $(libqsenet_la_LINK) -rpath $(libdir) $(libqsenet_la_OBJECTS) $(libqsenet_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -318,6 +319,7 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htrd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htre.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http.Plo@am__quote@ diff --git a/qse/lib/http/http.c b/qse/lib/net/htrd.c similarity index 80% rename from qse/lib/http/http.c rename to qse/lib/net/htrd.c index 8f31e56b..10f54928 100644 --- a/qse/lib/http/http.c +++ b/qse/lib/net/htrd.c @@ -1,5 +1,5 @@ /* - * $Id: http.c 341 2008-08-20 10:58:19Z baconevi $ + * $Id: htrd.c 341 2008-08-20 10:58:19Z baconevi $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -18,11 +18,11 @@ License along with QSE. If not, see . */ -#include +#include #include #include "../cmn/mem.h" -QSE_IMPLEMENT_COMMON_FUNCTIONS (http) +QSE_IMPLEMENT_COMMON_FUNCTIONS (htrd) static const qse_htoc_t NUL = '\0'; @@ -84,12 +84,12 @@ static QSE_INLINE int xdigit_to_num (qse_htoc_t c) } static QSE_INLINE int push_to_buffer ( - qse_http_t* http, qse_htob_t* octb, + qse_htrd_t* http, qse_htob_t* octb, const qse_htoc_t* ptr, qse_size_t len) { if (qse_mbs_ncat (octb, ptr, len) == (qse_size_t)-1) { - http->errnum = QSE_HTTP_ENOMEM; + http->errnum = QSE_HTRD_ENOMEM; return -1; } return 0; @@ -100,7 +100,7 @@ struct hdr_cmb_t struct hdr_cmb_t* next; }; -static QSE_INLINE void clear_combined_headers (qse_http_t* http) +static QSE_INLINE void clear_combined_headers (qse_htrd_t* http) { struct hdr_cmb_t* cmb = (struct hdr_cmb_t*)http->fed.chl; @@ -114,7 +114,7 @@ static QSE_INLINE void clear_combined_headers (qse_http_t* http) http->fed.chl = QSE_NULL; } -static QSE_INLINE void clear_feed (qse_http_t* http) +static QSE_INLINE void clear_feed (qse_htrd_t* http) { /* clear necessary part of the request/response before * reading the next request/response */ @@ -127,13 +127,13 @@ static QSE_INLINE void clear_feed (qse_http_t* http) QSE_MEMSET (&http->fed.s, 0, QSE_SIZEOF(http->fed.s)); } -#define QSE_HTTP_STATE_REQ 1 -#define QSE_HTTP_STATE_HDR 2 -#define QSE_HTTP_STATE_POST 3 +#define QSE_HTRD_STATE_REQ 1 +#define QSE_HTRD_STATE_HDR 2 +#define QSE_HTRD_STATE_POST 3 -qse_http_t* qse_http_open (qse_mmgr_t* mmgr, qse_size_t xtnsize) +qse_htrd_t* qse_htrd_open (qse_mmgr_t* mmgr, qse_size_t xtnsize) { - qse_http_t* http; + qse_htrd_t* http; if (mmgr == QSE_NULL) { @@ -145,12 +145,12 @@ qse_http_t* qse_http_open (qse_mmgr_t* mmgr, qse_size_t xtnsize) if (mmgr == QSE_NULL) return QSE_NULL; } - http = (qse_http_t*) QSE_MMGR_ALLOC ( - mmgr, QSE_SIZEOF(qse_http_t) + xtnsize + http = (qse_htrd_t*) QSE_MMGR_ALLOC ( + mmgr, QSE_SIZEOF(qse_htrd_t) + xtnsize ); if (http == QSE_NULL) return QSE_NULL; - if (qse_http_init (http, mmgr) == QSE_NULL) + if (qse_htrd_init (http, mmgr) == QSE_NULL) { QSE_MMGR_FREE (http->mmgr, http); return QSE_NULL; @@ -159,13 +159,13 @@ qse_http_t* qse_http_open (qse_mmgr_t* mmgr, qse_size_t xtnsize) return http; } -void qse_http_close (qse_http_t* http) +void qse_htrd_close (qse_htrd_t* http) { - qse_http_fini (http); + qse_htrd_fini (http); QSE_MMGR_FREE (http->mmgr, http); } -qse_http_t* qse_http_init (qse_http_t* http, qse_mmgr_t* mmgr) +qse_htrd_t* qse_htrd_init (qse_htrd_t* http, qse_mmgr_t* mmgr) { if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL(); @@ -174,11 +174,9 @@ qse_http_t* qse_http_init (qse_http_t* http, qse_mmgr_t* mmgr) qse_mbs_init (&http->fed.b.raw, http->mmgr, 0); qse_mbs_init (&http->fed.b.tra, http->mmgr, 0); - qse_mbs_init (&http->fed.b.pen, http->mmgr, 0); if (qse_htre_init (&http->re, mmgr) == QSE_NULL) { - qse_mbs_fini (&http->fed.b.pen); qse_mbs_fini (&http->fed.b.tra); qse_mbs_fini (&http->fed.b.raw); return QSE_NULL; @@ -187,22 +185,21 @@ qse_http_t* qse_http_init (qse_http_t* http, qse_mmgr_t* mmgr) return http; } -void qse_http_fini (qse_http_t* http) +void qse_htrd_fini (qse_htrd_t* http) { qse_htre_fini (&http->re); clear_combined_headers (http); - qse_mbs_fini (&http->fed.b.pen); qse_mbs_fini (&http->fed.b.tra); qse_mbs_fini (&http->fed.b.raw); } static qse_htoc_t* parse_initial_line ( - qse_http_t* http, qse_htoc_t* line) + qse_htrd_t* http, qse_htoc_t* line) { qse_htoc_t* p = line; - qse_htoc_t* tmp; - qse_size_t tmplen; + qse_htos_t tmp; + qse_http_method_t mtype; #if 0 /* ignore leading spaces excluding crlf */ @@ -213,88 +210,25 @@ static qse_htoc_t* parse_initial_line ( if (!is_upalpha_octet(*p)) goto badre; /* get the method name */ - tmp = p; + tmp.ptr = p; do { p++; } while (is_upalpha_octet(*p)); - tmplen = p - tmp; + tmp.len = p - tmp.ptr; - http->retype = QSE_HTTP_RETYPE_Q; - - /* test the method name */ - switch (tmplen) + http->retype = QSE_HTRD_RETYPE_Q; + if (qse_gethttpmethodtypefromstr (&tmp, &mtype) >= 0) { - case 3: - /* GET, PUT */ - if (tmp[0] == 'G' && tmp[1] == 'E' && tmp[2] == 'T') - { - http->re.re.quest.method = QSE_HTTP_REQ_GET; - break; - } - else if (tmp[0] == 'P' && tmp[1] == 'U' && tmp[2] == 'T') - { - http->re.re.quest.method = QSE_HTTP_REQ_PUT; - break; - } - goto badre; - - case 4: - /* POST, HEAD */ - if (tmp[0] == 'P' && tmp[1] == 'O' && tmp[2] == 'S' && tmp[3] == 'T') - { - http->re.re.quest.method = QSE_HTTP_REQ_POST; - break; - } - else if (tmp[0] == 'H' && tmp[1] == 'E' && tmp[2] == 'A' && tmp[3] == 'D') - { - http->re.re.quest.method = QSE_HTTP_REQ_HEAD; - break; - } - else if (tmp[0] == 'H' && tmp[1] == 'T' && tmp[2] == 'T' && tmp[3] == 'P') - { - http->retype = QSE_HTTP_RETYPE_S; - break; - } - /* TODO: more methods */ - goto badre; - - case 5: - /* TRACE */ - if (tmp[0] == 'T' && tmp[1] == 'R' && tmp[2] == 'A' && tmp[3] == 'C' && tmp[4] == 'E') - { - http->re.re.quest.method = QSE_HTTP_REQ_TRACE; - break; - } - goto badre; - - case 6: - /* DELETE */ - if (tmp[0] == 'D' && tmp[1] == 'E' && tmp[2] == 'L' && tmp[3] == 'E' && tmp[4] == 'T' && tmp[5] == 'E') - { - http->re.re.quest.method = QSE_HTTP_REQ_DELETE; - break; - } - goto badre; - - case 7: - /* OPTIONS, CONNECT */ - if (tmp[0] == 'O' && tmp[1] == 'P' && tmp[2] == 'T' && tmp[3] == 'I' && tmp[4] == 'O' && tmp[5] == 'N' && tmp[6] == 'S') - { - http->re.re.quest.method = QSE_HTTP_REQ_OPTIONS; - break; - } - else if (tmp[0] == 'C' && tmp[1] == 'O' && tmp[2] == 'N' && tmp[3] == 'N' && tmp[4] == 'E' && tmp[5] == 'C' && tmp[6] == 'T') - { - http->re.re.quest.method = QSE_HTTP_REQ_OPTIONS; - break; - } - goto badre; - - default: - goto badre; + qse_htre_setqmethod (&http->re, mtype); } - - if (http->retype == QSE_HTTP_RETYPE_S) + else if (qse_mbsxcmp (tmp.ptr, tmp.len, "HTTP") == 0) { - int n; + /* it begins with HTTP. it may be a response */ + http->retype = QSE_HTRD_RETYPE_S; + } + else goto badre; + + if (http->retype == QSE_HTRD_RETYPE_S) + { + int n, status; if (*p == '/' && p[1] != '\0' && p[2] == '.') { @@ -319,21 +253,27 @@ static qse_htoc_t* parse_initial_line ( n = digit_to_num(*p); if (n <= -1) goto badre; + status = 0; do { - http->re.re.sponse.code = http->re.re.sponse.code * 10 + n; + status = status * 10 + n; p++; } while ((n = digit_to_num(*p)) >= 0); /* status code must be followed by space */ if (!is_space_octet(*p)) goto badre; + + qse_htre_setsstatus (&http->re, status); + /* skip spaces */ do p++; while (is_space_octet(*p)); - http->re.re.sponse.message.ptr = p; + tmp.ptr = p; while (*p != '\0' && *p != '\n') p++; - http->re.re.sponse.message.len = p - http->re.re.sponse.message.ptr; + tmp.len = p - tmp.ptr; + + if (qse_htre_setsmessage (&http->re, &tmp) <= -1) goto outofmem; /* adjust Connection: close for HTTP 1.0 or eariler */ if (http->re.version.major < 1 || @@ -344,6 +284,9 @@ static qse_htoc_t* parse_initial_line ( } else { + qse_htoc_t* out; + qse_htos_t param; + /* method name must be followed by space */ if (!is_space_octet(*p)) goto badre; @@ -351,12 +294,10 @@ static qse_htoc_t* parse_initial_line ( do p++; while (is_space_octet(*p)); /* process the url part */ - http->re.re.quest.path.ptr = p; - #if 0 - http->re.re.quest.args.ptr = QSE_NULL; - #endif + tmp.ptr = p; /* remember the beginning of path*/ + param.ptr = QSE_NULL; - tmp = p; + out = p; while (*p != '\0' && !is_space_octet(*p)) { if (*p == '%') @@ -373,41 +314,42 @@ static qse_htoc_t* parse_initial_line ( goto badre; } - *tmp++ = t; + *out++ = t; p += 3; } - else *tmp++ = *p++; + else *out++ = *p++; } - #if 0 else if (*p == '?') { - if (!http->re.re.quest.args.ptr) + if (!param.ptr) { /* ? must be explicit to be a argument instroducer. * %3f is just a literal. */ - http->re.re.quest.path.len = tmp - http->re.re.quest.path.ptr; - *tmp++ = '\0'; - http->re.re.quest.args.ptr = tmp; + tmp.len = out - tmp.ptr; + *out++ = '\0'; /* null-terminate the path part */ + param.ptr = out; p++; } - else *tmp++ = *p++; + else *out++ = *p++; } - #endif - else *tmp++ = *p++; + else *out++ = *p++; } /* the url must be followed by a space */ if (!is_space_octet(*p)) goto badre; - #if 0 - if (http->re.re.quest.args.ptr) - http->re.re.quest.args.len = tmp - http->re.re.quest.args.ptr; - else - #endif - http->re.re.quest.path.len = tmp - http->re.re.quest.path.ptr; - /* null-terminate the url part though we record the length */ - *tmp = '\0'; - + /* null-terminate the url part though we know the length */ + *out = '\0'; + + if (param.ptr) + { + param.len = out - param.ptr; + if (qse_htre_setqparamstr (&http->re, param.ptr) <= -1) goto outofmem; + } + else tmp.len = out - tmp.ptr; + + if (qse_htre_setqpath (&http->re, &tmp) <= -1) goto outofmem; + /* skip spaces after the url part */ do { p++; } while (is_space_octet(*p)); @@ -447,31 +389,36 @@ static qse_htoc_t* parse_initial_line ( return ++p; badre: - http->errnum = QSE_HTTP_EBADRE; + http->errnum = QSE_HTRD_EBADRE; return QSE_NULL; + +outofmem: + http->errnum = QSE_HTRD_ENOMEM; + return QSE_NULL; + } -void qse_http_clear (qse_http_t* http) +void qse_htrd_clear (qse_htrd_t* http) { clear_feed (http); } -int qse_http_getoption (qse_http_t* http) +int qse_htrd_getoption (qse_htrd_t* http) { return http->option; } -void qse_http_setoption (qse_http_t* http, int opts) +void qse_htrd_setoption (qse_htrd_t* http, int opts) { http->option = opts; } -const qse_http_recbs_t* qse_http_getrecbs (qse_http_t* http) +const qse_htrd_recbs_t* qse_htrd_getrecbs (qse_htrd_t* http) { return &http->recbs; } -void qse_http_setrecbs (qse_http_t* http, const qse_http_recbs_t* recbs) +void qse_htrd_setrecbs (qse_htrd_t* http, const qse_htrd_recbs_t* recbs) { http->recbs = *recbs; } @@ -504,7 +451,7 @@ static QSE_INLINE int compare_octets ( } static QSE_INLINE int capture_connection ( - qse_http_t* http, qse_htb_pair_t* pair) + qse_htrd_t* http, qse_htb_pair_t* pair) { int n; @@ -527,7 +474,7 @@ static QSE_INLINE int capture_connection ( } static QSE_INLINE int capture_content_length ( - qse_http_t* http, qse_htb_pair_t* pair) + qse_htrd_t* http, qse_htb_pair_t* pair) { qse_size_t len = 0, off = 0, tmp; const qse_htoc_t* ptr = QSE_HTB_VPTR(pair); @@ -538,7 +485,7 @@ static QSE_INLINE int capture_content_length ( if (num <= -1) { /* the length contains a non-digit */ - http->errnum = QSE_HTTP_EBADRE; + http->errnum = QSE_HTRD_EBADRE; return -1; } @@ -546,7 +493,7 @@ static QSE_INLINE int capture_content_length ( if (tmp < len) { /* the length has overflown */ - http->errnum = QSE_HTTP_EBADRE; + http->errnum = QSE_HTRD_EBADRE; return -1; } @@ -557,7 +504,7 @@ static QSE_INLINE int capture_content_length ( if (off == 0) { /* no length was provided */ - http->errnum = QSE_HTTP_EBADRE; + http->errnum = QSE_HTRD_EBADRE; return -1; } @@ -565,7 +512,7 @@ static QSE_INLINE int capture_content_length ( { /* content-length is greater than 0 * while transfer-encoding: chunked is specified. */ - http->errnum = QSE_HTTP_EBADRE; + http->errnum = QSE_HTRD_EBADRE; return -1; } @@ -573,16 +520,8 @@ static QSE_INLINE int capture_content_length ( return 0; } -static QSE_INLINE int capture_content_type ( - qse_http_t* http, qse_htb_pair_t* pair) -{ - http->re.attr.content_type.ptr = QSE_HTB_VPTR(pair); - http->re.attr.content_type.len = QSE_HTB_VLEN(pair); - return 0; -} - static QSE_INLINE int capture_expect ( - qse_http_t* http, qse_htb_pair_t* pair) + qse_htrd_t* http, qse_htb_pair_t* pair) { int n; @@ -598,16 +537,8 @@ static QSE_INLINE int capture_expect ( return 0; } -static QSE_INLINE int capture_host ( - qse_http_t* http, qse_htb_pair_t* pair) -{ - http->re.attr.host.ptr = QSE_HTB_VPTR(pair); - http->re.attr.host.len = QSE_HTB_VLEN(pair); - return 0; -} - static QSE_INLINE int capture_transfer_encoding ( - qse_http_t* http, qse_htb_pair_t* pair) + qse_htrd_t* http, qse_htb_pair_t* pair) { int n; @@ -627,25 +558,23 @@ static QSE_INLINE int capture_transfer_encoding ( /* other encoding type not supported yet */ badre: - http->errnum = QSE_HTTP_EBADRE; + http->errnum = QSE_HTRD_EBADRE; return -1; } static QSE_INLINE int capture_key_header ( - qse_http_t* http, qse_htb_pair_t* pair) + qse_htrd_t* http, qse_htb_pair_t* pair) { static struct { const qse_htoc_t* ptr; qse_size_t len; - int (*handler) (qse_http_t*, qse_htb_pair_t*); + int (*handler) (qse_htrd_t*, qse_htb_pair_t*); } hdrtab[] = { { "Connection", 10, capture_connection }, { "Content-Length", 14, capture_content_length }, - { "Content-Type", 12, capture_content_type }, { "Expect", 6, capture_expect }, - { "Host", 4, capture_host }, { "Transfer-Encoding", 17, capture_transfer_encoding } }; @@ -677,7 +606,7 @@ static QSE_INLINE int capture_key_header ( struct hdr_cbserter_ctx_t { - qse_http_t* http; + qse_htrd_t* http; void* vptr; qse_size_t vlen; }; @@ -695,7 +624,7 @@ static qse_htb_pair_t* hdr_cbserter ( p = qse_htb_allocpair (htb, kptr, klen, tx->vptr, tx->vlen); - if (p == QSE_NULL) tx->http->errnum = QSE_HTTP_ENOMEM; + if (p == QSE_NULL) tx->http->errnum = QSE_HTRD_ENOMEM; else { if (capture_key_header (tx->http, p) <= -1) @@ -736,7 +665,7 @@ static qse_htb_pair_t* hdr_cbserter ( ); if (cmb == QSE_NULL) { - tx->http->errnum = QSE_HTTP_ENOMEM; + tx->http->errnum = QSE_HTRD_ENOMEM; return QSE_NULL; } @@ -785,7 +714,7 @@ Change it to doubly linked for this? } } -qse_htoc_t* parse_header_fields (qse_http_t* http, qse_htoc_t* line) +qse_htoc_t* parse_header_fields (qse_htrd_t* http, qse_htoc_t* line) { qse_htoc_t* p = line, * last; struct @@ -859,13 +788,13 @@ qse_htoc_t* parse_header_fields (qse_http_t* http, qse_htoc_t* line) ctx.vptr = value.ptr; ctx.vlen = value.len; - http->errnum = QSE_HTTP_ENOERR; + http->errnum = QSE_HTRD_ENOERR; if (qse_htb_cbsert ( &http->re.hdrtab, name.ptr, name.len, hdr_cbserter, &ctx) == QSE_NULL) { - if (http->errnum == QSE_HTTP_ENOERR) - http->errnum = QSE_HTTP_ENOMEM; + if (http->errnum == QSE_HTRD_ENOERR) + http->errnum = QSE_HTRD_ENOMEM; return QSE_NULL; } } @@ -873,12 +802,12 @@ qse_htoc_t* parse_header_fields (qse_http_t* http, qse_htoc_t* line) return p; badhdr: - http->errnum = QSE_HTTP_EBADHDR; + http->errnum = QSE_HTRD_EBADHDR; return QSE_NULL; } static QSE_INLINE int parse_initial_line_and_headers ( - qse_http_t* http, const qse_htoc_t* req, qse_size_t rlen) + qse_htrd_t* http, const qse_htoc_t* req, qse_size_t rlen) { qse_htoc_t* p; @@ -890,7 +819,7 @@ static QSE_INLINE int parse_initial_line_and_headers ( p = QSE_MBS_PTR(&http->fed.b.raw); - if (http->option & QSE_HTTP_LEADINGEMPTYLINES) + if (http->option & QSE_HTRD_LEADINGEMPTYLINES) while (is_whspace_octet(*p)) p++; else while (is_space_octet(*p)) p++; @@ -925,7 +854,7 @@ static QSE_INLINE int parse_initial_line_and_headers ( #define GET_CHUNK_CRLF 3 #define GET_CHUNK_TRAILERS 4 -static const qse_htoc_t* getchunklen (qse_http_t* http, const qse_htoc_t* ptr, qse_size_t len) +static const qse_htoc_t* getchunklen (qse_htrd_t* http, const qse_htoc_t* ptr, qse_size_t len) { const qse_htoc_t* end = ptr + len; @@ -985,7 +914,7 @@ static const qse_htoc_t* getchunklen (qse_http_t* http, const qse_htoc_t* ptr, q else { //qse_printf (QSE_T("XXXXXXXXXXXXXXXXXxxx [%c]\n"), *ptr); - http->errnum = QSE_HTTP_EBADRE; + http->errnum = QSE_HTRD_EBADRE; return QSE_NULL; } } @@ -994,7 +923,7 @@ static const qse_htoc_t* getchunklen (qse_http_t* http, const qse_htoc_t* ptr, q } static const qse_htoc_t* get_trailing_headers ( - qse_http_t* http, const qse_htoc_t* req, const qse_htoc_t* end) + qse_htrd_t* http, const qse_htoc_t* req, const qse_htoc_t* end) { const qse_htoc_t* ptr = req; @@ -1007,7 +936,7 @@ static const qse_htoc_t* get_trailing_headers ( case '\0': /* guarantee that the request does not contain a null * character */ - http->errnum = QSE_HTTP_EBADRE; + http->errnum = QSE_HTRD_EBADRE; return QSE_NULL; case '\n': @@ -1069,7 +998,7 @@ done: } /* feed the percent encoded string */ -int qse_http_feed (qse_http_t* http, const qse_htoc_t* req, qse_size_t len) +int qse_htrd_feed (qse_htrd_t* http, const qse_htoc_t* req, qse_size_t len) { const qse_htoc_t* end = req + len; const qse_htoc_t* ptr = req; @@ -1104,7 +1033,7 @@ int qse_http_feed (qse_http_t* http, const qse_htoc_t* req, qse_size_t len) { register qse_htoc_t b = *ptr++; - if (http->option & QSE_HTTP_LEADINGEMPTYLINES && + if (http->option & QSE_HTRD_LEADINGEMPTYLINES && http->fed.s.plen <= 0 && is_whspace_octet(b)) { /* let's drop leading whitespaces across multiple @@ -1118,7 +1047,7 @@ int qse_http_feed (qse_http_t* http, const qse_htoc_t* req, qse_size_t len) case '\0': /* guarantee that the request does not contain * a null character */ - http->errnum = QSE_HTTP_EBADRE; + http->errnum = QSE_HTRD_EBADRE; return -1; case '\n': @@ -1153,7 +1082,7 @@ int qse_http_feed (qse_http_t* http, const qse_htoc_t* req, qse_size_t len) if (parse_initial_line_and_headers (http, req, ptr - req) <= -1) return -1; - if (http->retype == QSE_HTTP_RETYPE_Q && + if (http->retype == QSE_HTRD_RETYPE_Q && http->re.attr.expect_continue && http->recbs.expect_continue && ptr >= end) { @@ -1170,8 +1099,8 @@ int qse_http_feed (qse_http_t* http, const qse_htoc_t* req, qse_size_t len) if (n <= -1) { - if (http->errnum == QSE_HTTP_ENOERR) - http->errnum = QSE_HTTP_EREQCBS; + if (http->errnum == QSE_HTRD_ENOERR) + http->errnum = QSE_HTRD_EREQCBS; /* need to clear request on error? clear_feed (http); */ @@ -1287,7 +1216,7 @@ int qse_http_feed (qse_http_t* http, const qse_htoc_t* req, qse_size_t len) else { /* redundant character ... */ - http->errnum = QSE_HTTP_EBADRE; + http->errnum = QSE_HTRD_EBADRE; return -1; } } @@ -1302,9 +1231,9 @@ int qse_http_feed (qse_http_t* http, const qse_htoc_t* req, qse_size_t len) { int n; - http->errnum = QSE_HTTP_ENOERR; + http->errnum = QSE_HTRD_ENOERR; - if (http->retype == QSE_HTTP_RETYPE_S) + if (http->retype == QSE_HTRD_RETYPE_S) { QSE_ASSERTX ( http->recbs.response != QSE_NULL, @@ -1325,8 +1254,8 @@ int qse_http_feed (qse_http_t* http, const qse_htoc_t* req, qse_size_t len) if (n <= -1) { - if (http->errnum == QSE_HTTP_ENOERR) - http->errnum = QSE_HTTP_EREQCBS; + if (http->errnum == QSE_HTRD_ENOERR) + http->errnum = QSE_HTRD_EREQCBS; /* need to clear request on error? clear_feed (http); */ @@ -1368,3 +1297,28 @@ feedme_more: return 0; } +int qse_htrd_read (qse_htrd_t* http) +{ + qse_ssize_t n; + + QSE_ASSERTX ( + http->recbs.reader != QSE_NULL, + "You must set the octet reader to be able to call qse_htrd_read()" + ); + + http->errnum = QSE_HTRD_ENOERR; + n = http->recbs.reader (http, http->rbuf, QSE_SIZEOF(http->rbuf)); + if (n <= -1) + { + if (http->errnum == QSE_HTRD_ENOERR) http->errnum = QSE_HTRD_EREADER; + return -1; + } + if (n == 0) + { + http->errnum = QSE_HTRD_EDISCON; + return -1; + } + + return qse_htrd_feed (http, http->rbuf, n); +} + diff --git a/qse/lib/net/htre.c b/qse/lib/net/htre.c new file mode 100644 index 00000000..5e185db6 --- /dev/null +++ b/qse/lib/net/htre.c @@ -0,0 +1,68 @@ +/* + * $Id$ + */ + +#include +#include "../cmn/mem.h" + +qse_htre_t* qse_htre_init (qse_htre_t* re, qse_mmgr_t* mmgr) +{ + QSE_MEMSET (re, 0, QSE_SIZEOF(*re)); + re->mmgr = mmgr; + + if (qse_htb_init (&re->hdrtab, mmgr, 60, 70, 1, 1) == QSE_NULL) + { + return QSE_NULL; + } + + qse_mbs_init (&re->content, mmgr, 0); + + qse_mbs_init (&re->qpath_or_smesg, mmgr, 0); + qse_mbs_init (&re->qparamstr, mmgr, 0); + + return re; +} + +void qse_htre_fini (qse_htre_t* re) +{ + qse_mbs_fini (&re->qparamstr); + qse_mbs_fini (&re->qpath_or_smesg); + qse_mbs_fini (&re->content); + qse_htb_fini (&re->hdrtab); +} + +void qse_htre_clear (qse_htre_t* re) +{ + QSE_MEMSET (&re->version, 0, QSE_SIZEOF(re->version)); + QSE_MEMSET (&re->attr, 0, QSE_SIZEOF(re->attr)); + + qse_htb_clear (&re->hdrtab); + + qse_mbs_clear (&re->content); + qse_mbs_clear (&re->qpath_or_smesg); + qse_mbs_clear (&re->qparamstr); + + re->discard = 0; +} + +int qse_htre_setbuf ( + qse_htre_t* re, qse_htob_t* buf, const qse_htos_t* str) +{ + qse_mbs_clear (buf); + return (qse_mbs_ncat (buf, str->ptr, str->len) == (qse_size_t)-1)? -1: 0; +} + +void qse_htre_getbuf ( + qse_htre_t* re, const qse_htob_t* buf, qse_htos_t* str) +{ + str->ptr = QSE_MBS_PTR(buf); + str->len = QSE_MBS_LEN(buf); +} + +int qse_htre_setqparamstr (qse_htre_t* re, const qse_htoc_t* str) + +{ + return (qse_mbs_cpy (&re->qparamstr, str) == (qse_size_t)-1)? -1: 0; +} + + diff --git a/qse/lib/net/http.c b/qse/lib/net/http.c new file mode 100644 index 00000000..e5d0cc44 --- /dev/null +++ b/qse/lib/net/http.c @@ -0,0 +1,175 @@ +/* + * $Id: http.c 341 2008-08-20 10:58:19Z baconevi $ + * + Copyright 2006-2011 Chung, Hyung-Hwan. + This file is part of QSE. + + QSE is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + QSE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with QSE. If not, see . + */ + +#include +#include +#include + +const qse_htoc_t* qse_gethttpmethodname (qse_http_method_t type) +{ + static qse_htoc_t* names[] = + { + "GET", + "HEAD", + "POST", + "PUT", + "DELETE", + "TRACE", + "OPTIONS", + "CONNECT" + }; + + return (type < 0 || type >= QSE_COUNTOF(names))? QSE_NULL: names[type]; +} + +struct mtab_t +{ + const qse_htoc_t* name; + qse_http_method_t type; +}; + +static struct mtab_t mtab[] = +{ + { "CONNECT", QSE_HTTP_CONNECT }, + { "DELETE", QSE_HTTP_DELETE }, + { "GET", QSE_HTTP_GET }, + { "HEAD", QSE_HTTP_HEAD }, + { "OPTIONS", QSE_HTTP_OPTIONS }, + { "POST", QSE_HTTP_POST }, + { "PUT", QSE_HTTP_PUT }, + { "TRACE", QSE_HTTP_TRACE } +}; + +int qse_gethttpmethodtype ( + const qse_htoc_t* name, + qse_http_method_t* type) +{ + + /* 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; + 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 + { + *type = entry->type; + return 0; + } + } + + return -1; +} + +int qse_gethttpmethodtypefromstr ( + const qse_htos_t* name, + qse_http_method_t* type) +{ + /* 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; + 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 + { + *type = entry->type; + return 0; + } + } + + return -1; +} + +int qse_scanhttpparamstr ( + const qse_htoc_t* paramstr, + qse_scanhttpparamstr_callback_t callback, + void* ctx) +{ + qse_mcstr_t key, val; + const qse_htoc_t* p = paramstr; + + key.ptr = p; key.len = 0; + val.ptr = QSE_NULL; val.len = 0; + + while (1) + { + if (*p == '&' || *p == ';' || *p == '\0') + { + QSE_ASSERT (key.ptr != QSE_NULL); + if (val.ptr == QSE_NULL) val.ptr = ""; + + if (callback (ctx, &key, &val) <= -1) return -1; + + if (*p == '\0') break; + + key.ptr = ++p; key.len = 0; + val.ptr = QSE_NULL; val.len = 0; + } + else if (*p == '=') + { + val.ptr = ++p; + val.len = 0; + } + else + { + if (val.ptr) val.len++; + else key.len++; + } + } + + return 0; +} diff --git a/qse/lib/stx/par.c b/qse/lib/stx/par.c index 08d9a884..b1541613 100644 --- a/qse/lib/stx/par.c +++ b/qse/lib/stx/par.c @@ -117,6 +117,11 @@ qse_stc_t* qse_stc_init (qse_stc_t* stc, qse_mmgr_t* mmgr, qse_stx_t* stx) } stc->token.type = TOKEN_END; +/* TODO:create a bytearray data type... + * i think i can reuse qse_mbs_t ... by dropping the null-termination part... +qse_bar_t bryte array.... +qse_lba_t linear byte array + */ if (qse_lda_init ( &stc->bytecode, mmgr, 256, QSE_SIZEOF(qse_byte_t), QSE_NULL) == QSE_NULL) diff --git a/qse/samples/http/Makefile.am b/qse/samples/net/Makefile.am similarity index 66% rename from qse/samples/http/Makefile.am rename to qse/samples/net/Makefile.am index f8bf1f90..c72c98de 100644 --- a/qse/samples/http/Makefile.am +++ b/qse/samples/net/Makefile.am @@ -7,8 +7,8 @@ AM_CPPFLAGS = \ bin_PROGRAMS = http01 -LDFLAGS = -L../../lib/cmn -L../../lib/http -LDADD = -lqsehttp -lqsecmn $(LIBM) -lpthread +LDFLAGS = -L../../lib/cmn -L../../lib/net +LDADD = -lqsenet -lqsecmn $(LIBM) -lpthread http01_SOURCES = http01.c diff --git a/qse/samples/http/Makefile.in b/qse/samples/net/Makefile.in similarity index 98% rename from qse/samples/http/Makefile.in rename to qse/samples/net/Makefile.in index 51b30888..60304230 100644 --- a/qse/samples/http/Makefile.in +++ b/qse/samples/net/Makefile.in @@ -35,7 +35,7 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = http01$(EXEEXT) -subdir = samples/http +subdir = samples/net DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ @@ -111,7 +111,7 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ -LDFLAGS = -L../../lib/cmn -L../../lib/http +LDFLAGS = -L../../lib/cmn -L../../lib/net LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ @@ -216,7 +216,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/include \ -I$(includedir) -LDADD = -lqsehttp -lqsecmn $(LIBM) -lpthread +LDADD = -lqsenet -lqsecmn $(LIBM) -lpthread http01_SOURCES = http01.c all: all-am @@ -231,9 +231,9 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign samples/http/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign samples/net/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign samples/http/Makefile + $(AUTOMAKE) --foreign samples/net/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff --git a/qse/samples/http/http01.c b/qse/samples/net/http01.c similarity index 80% rename from qse/samples/http/http01.c rename to qse/samples/net/http01.c index ec3a5237..4d53d36a 100644 --- a/qse/samples/http/http01.c +++ b/qse/samples/net/http01.c @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -60,7 +60,7 @@ struct client_t { int fd; struct sockaddr_storage addr; - qse_http_t* http; + qse_htrd_t* http; pthread_mutex_t action_mutex; struct @@ -163,8 +163,90 @@ static int enqueue_sendtext_locked (client_t* client, const char* text) return enqueue_client_action_locked (client, &action); } -static int enqueue_sendfmt_locked (client_t* client, const char* fmt, ...) +static int format_and_do (int (*task) (void* arg, char* text), void* arg, const char* fmt, ...) { + va_list ap; + char n[2]; + char* buf; + int bytes_req; + + va_start (ap, fmt); +#if defined(_WIN32) && defined(_MSC_VER) + bytes_req = _vsnprintf (n, 1, fmt, ap); +#else + bytes_req = vsnprintf (n, 1, fmt, ap); +#endif + va_end (ap); + if (bytes_req == -1) + { + qse_size_t capa = 256; + buf = (char*) malloc (capa + 1); + + /* an old vsnprintf behaves differently from C99 standard. + * thus, it returns -1 when it can't write all the input given. */ + for (;;) + { + int l; + va_start (ap, fmt); +#if defined(_WIN32) && defined(_MSC_VER) + if ((l = _vsnprintf (buf, capa + 1, fmt, ap)) == -1) +#else + if ((l = vsnprintf (buf, capa + 1, fmt, ap)) == -1) +#endif + { + va_end (ap); + + free (buf); + capa = capa * 2; + buf = (char*)malloc (capa + 1); + if (buf == NULL) return -1; + + continue; + } + + va_end (ap); + break; + } + } + else + { + /* vsnprintf returns the number of characters that would + * have been written not including the terminating '\0' + * if the _data buffer were large enough */ + buf = (char*)malloc (bytes_req + 1); + if (buf == NULL) return -1; + + va_start (ap, fmt); +#if defined(_WIN32) && defined(_MSC_VER) + _vsnprintf (buf, bytes_req + 1, fmt, ap); +#else + vsnprintf (buf, bytes_req + 1, fmt, ap); +#endif + + //_data[_size] = '\0'; + va_end (ap); + } + + return task (arg, buf); +} + +static int enqueue_format (void* arg, char* text) +{ + client_t* client = (client_t*)arg; + + client_action_t action; + + memset (&action, 0, sizeof(action)); + action.type = ACTION_SENDTEXTDUP; + action.u.sendtextdup.ptr = text; + action.u.sendtextdup.left = strlen(text); + + if (enqueue_client_action_locked (client, &action) <= -1) + { + free (text); + return -1; + } + return 0; } @@ -221,16 +303,28 @@ qse_printf (QSE_T("HEADER OK %d[%S] %d[%S]\n"), (int)QSE_HTB_KLEN(pair), QSE_HT return QSE_HTB_WALK_FORWARD; } -static int handle_request (qse_http_t* http, qse_htre_t* req) +static capture_param (void* ctx, const qse_mcstr_t* key, const qse_mcstr_t* val) { - http_xtn_t* xtn = (http_xtn_t*) qse_http_getxtn (http); +} + +static int handle_request (qse_htrd_t* http, qse_htre_t* req) +{ + http_xtn_t* xtn = (http_xtn_t*) qse_htrd_getxtn (http); client_t* client = &xtn->array->data[xtn->index]; + int method; qse_printf (QSE_T("================================\n")); qse_printf (QSE_T("REQUEST ==> [%S] version[%d.%d] method[%d]\n"), - req->re.quest.path.ptr, req->version.major, req->version.minor, req->re.quest.method); + qse_htre_getqpathptr(req), + qse_htre_getmajorversion(req), + qse_htre_getminorversion(req), + qse_htre_getqmethod(req) +); +if (qse_htre_getqparamslen(req) > 0) +{ +qse_printf (QSE_T("PARAMS ==> [%S]\n"), qse_htre_getqparamsptr(req)); +} -if (req->attr.host.ptr) qse_printf (QSE_T("HOST===> %S\n"), req->attr.host.ptr); qse_htb_walk (&http->re.hdrtab, walk, QSE_NULL); if (QSE_MBS_LEN(&http->re.content) > 0) { @@ -239,30 +333,29 @@ qse_printf (QSE_T("content = [%.*S]\n"), QSE_MBS_PTR(&http->re.content)); } + method = qse_htre_getqmethod (req); - if (req->re.quest.method == QSE_HTTP_REQ_GET || req->re.quest.method == QSE_HTTP_REQ_POST) + if (method == QSE_HTTP_GET || method == QSE_HTTP_POST) { - qse_htre_decodereqpath (req, ); + //qse_htre_decodereqpath (req, ); /* original path not available anymore */ - int fd = open (req->re.quest.path.ptr, O_RDONLY); + qse_scanhttpparamstr (qse_htre_getqparamstrptr(req), capture_param, xxx); + + int fd = open (qse_htre_getqpathptr(req), O_RDONLY); if (fd <= -1) { -char text[256]; const char* msg = "NOT FOUNDREQUESTD FILE NOT FOUND"; -snprintf (text, sizeof(text), +if (format_and_do (enqueue_format, client, "HTTP/%d.%d 404 Not found\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n", req->version.major, req->version.minor, - (int)strlen(msg) + 4, msg); - -qse_printf (QSE_T("open failure.... sending 404 not found\n")); - - if (enqueue_sendtextdup_locked (client, text) <= -1) - { + (int)strlen(msg) + 4, msg) <= -1) +{ qse_printf (QSE_T("failed to push action....\n")); - return -1; - } + return -1; +} + } else { @@ -279,7 +372,7 @@ qse_printf (QSE_T("fstat failure....\n")); qse_printf (QSE_T("empty file....\n")); #if 0 - qse_htre_t* res = qse_http_newresponse (http); + qse_htre_t* res = qse_htrd_newresponse (http); if (req == QSE_NULL) { /* hard failure... can't answer */ @@ -287,7 +380,7 @@ qse_printf (QSE_T("empty file....\n")); } - ptr = qse_http_emitresponse (http, res, &len); + ptr = qse_htrd_emitresponse (http, res, &len); if (ptr == QSE_NULL) { /* hard failure... can't answer */ @@ -301,11 +394,13 @@ qse_printf (QSE_T("empty file....\n")); } else { + char text[128]; snprintf (text, sizeof(text), "HTTP/%d.%d 200 OK\r\nContent-Length: %llu\r\n\r\n", - req->version.major, - req->version.minor, (unsigned long long)st.st_size); + qse_htre_getmajorversion(req), + qse_htre_getminorversion(req), + (unsigned long long)st.st_size); #if 0 if (enqueue_sendfmt_locked (client, @@ -347,8 +442,9 @@ char text[256]; const char* msg = "Method not allowedMETHOD NOT ALLOWED"; snprintf (text, sizeof(text), "HTTP/%d.%d 405 Method not allowed\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n", - req->version.major, - req->version.minor, (int)strlen(msg)+4, msg); + qse_htre_getmajorversion(req), + qse_htre_getminorversion(req), + (int)strlen(msg)+4, msg); if (enqueue_sendtextdup_locked (client, text) <= -1) { qse_printf (QSE_T("failed to push action....\n")); @@ -361,12 +457,25 @@ return -1; return 0; } -static int handle_expect_continue (qse_http_t* http, qse_htre_t* req) +static int handle_expect_continue (qse_htrd_t* http, qse_htre_t* req) { - http_xtn_t* xtn = (http_xtn_t*) qse_http_getxtn (http); + http_xtn_t* xtn = (http_xtn_t*) qse_htrd_getxtn (http); client_t* client = &xtn->array->data[xtn->index]; - if (req->re.quest.method == QSE_HTTP_REQ_GET) + if (qse_htre_getqmethod(req) == QSE_HTTP_POST) + { + char text[32]; + + snprintf (text, sizeof(text), + "HTTP/%d.%d 100 OK\r\n\r\n", + req->version.major, req->version.minor); + + if (enqueue_sendtextdup_locked (client, text) <= -1) + { + return -1; + } + } + else { char text[32]; @@ -381,24 +490,11 @@ static int handle_expect_continue (qse_http_t* http, qse_htre_t* req) return -1; } } - else - { - char text[32]; - - snprintf (text, sizeof(text), - "HTTP/%d.%d 100 OK\r\n\r\n", - req->version.major, req->version.minor); - - if (enqueue_sendtextdup_locked (client, text) <= -1) - { - return -1; - } - } return 0; } -static int handle_response (qse_http_t* http, qse_htre_t* res) +static int handle_response (qse_htrd_t* http, qse_htre_t* res) { #if 0 if (res->code >= 100 && res->code <= 199) @@ -408,13 +504,31 @@ static int handle_response (qse_http_t* http, qse_htre_t* res) #endif qse_printf (QSE_T("response received... HTTP/%d.%d %d %.*S\n"), - res->version.major, res->version.minor, res->re.sponse.code, - (int)res->re.sponse.message.len, res->re.sponse.message.ptr); + qse_htre_getmajorversion(res), + qse_htre_getminorversion(res), + qse_htre_getsstatus(res), + (int)qse_htre_getsmessagelen(res), + qse_htre_getsmessageptr(res) + ); return -1; } -qse_http_recbs_t http_recbs = +static qse_ssize_t receive_octets (qse_htrd_t* http, qse_htoc_t* buf, qse_size_t size) { + http_xtn_t* xtn = (http_xtn_t*) qse_htrd_getxtn (http); + client_t* client = &xtn->array->data[xtn->index]; + ssize_t n; + + n = recv (client->fd, buf, size, 0); + if (n <= -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) + http->errnum = 99999; + + return n; +} + +qse_htrd_recbs_t http_recbs = +{ + receive_octets, handle_request, handle_response, handle_expect_continue @@ -469,7 +583,7 @@ static void delete_from_client_array (client_array_t* array, int fd) purge_client_actions_locked (&array->data[fd]); pthread_mutex_destroy (&array->data[fd].action_mutex); - qse_http_close (array->data[fd].http); + qse_htrd_close (array->data[fd].http); array->data[fd].http = QSE_NULL; close (array->data[fd].fd); array->size--; @@ -518,15 +632,15 @@ static client_t* insert_into_client_array ( array->data[fd].fd = fd; array->data[fd].addr = *addr; - array->data[fd].http = qse_http_open (QSE_MMGR_GETDFL(), QSE_SIZEOF(*xtn)); + array->data[fd].http = qse_htrd_open (QSE_MMGR_GETDFL(), QSE_SIZEOF(*xtn)); if (array->data[fd].http == QSE_NULL) return QSE_NULL; pthread_mutex_init (&array->data[fd].action_mutex, NULL); - xtn = (http_xtn_t*)qse_http_getxtn (array->data[fd].http); + xtn = (http_xtn_t*)qse_htrd_getxtn (array->data[fd].http); xtn->array = array; xtn->index = fd; - qse_http_setrecbs (array->data[fd].http, &http_recbs); + qse_htrd_setrecbs (array->data[fd].http, &http_recbs); array->size++; return &array->data[fd]; } @@ -653,6 +767,9 @@ qse_printf (QSE_T("finished sending text dup...\n")); if (count >= action->u.sendfile.left) count = action->u.sendfile.left; +//n = qse_htrd_write (client->http, sendfile, joins); + + n = sendfile ( client->fd, action->u.sendfile.fd, @@ -858,48 +975,19 @@ qse_printf (QSE_T("connection %d accepted\n"), c); if (FD_ISSET(client->fd, &r)) { /* got input */ - - qse_htoc_t buf[1024]; - ssize_t m; - - reread: - m = read (client->fd, buf, sizeof(buf)); - if (m <= -1) + if (qse_htrd_read (client->http) <= -1) { - if (errno != EINTR) + int errnum = client->http->errnum; + if (errnum != 99999) { pthread_mutex_lock (&appdata.camutex); delete_from_client_array (&appdata.ca, fd); pthread_mutex_unlock (&appdata.camutex); - qse_fprintf (QSE_STDERR, QSE_T("Error: failed to read from a client %d\n"), fd); - continue; + if (errnum == QSE_HTRD_EDISCON) + qse_fprintf (QSE_STDERR, QSE_T("Debug: connection closed %d\n"), client->fd); + else + qse_fprintf (QSE_STDERR, QSE_T("Error: failed to read/process a request from a client %d\n"), client->fd); } - goto reread; - } - else if (m == 0) - { - pthread_mutex_lock (&appdata.camutex); - delete_from_client_array (&appdata.ca, fd); - pthread_mutex_unlock (&appdata.camutex); - qse_fprintf (QSE_STDERR, QSE_T("Debug: connection closed %d\n"), fd); - continue; - } - - /* feed may have called the request callback multiple times... - * that's because we don't know how many valid requests - * are included in 'buf' */ - n = qse_http_feed (client->http, buf, m); - if (n <= -1) - { - if (client->http->errnum == QSE_HTTP_EBADRE) - { - /* TODO: write a response to indicate bad request... */ - } - - pthread_mutex_lock (&appdata.camutex); - delete_from_client_array (&appdata.ca, fd); - pthread_mutex_unlock (&appdata.camutex); - qse_fprintf (QSE_STDERR, QSE_T("Error: http error while processing \n")); continue; } }