From 470c2921574bf82e3f16b3514eb2590d3fefbdc6 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Fri, 5 Aug 2011 09:43:28 +0000 Subject: [PATCH] added more checks to cgi handling --- qse/include/qse/cmn/Makefile.am | 1 + qse/include/qse/cmn/Makefile.in | 13 +-- qse/include/qse/cmn/env.h | 88 ++++++++++++++++++++ qse/include/qse/cmn/pio.h | 10 +-- qse/include/qse/cmn/str.h | 112 +++++++++++++++++++++++-- qse/include/qse/net/httpd.h | 3 +- qse/lib/cmn/Makefile.am | 1 + qse/lib/cmn/Makefile.in | 4 +- qse/lib/cmn/env.c | 91 +++++++++++++++++++++ qse/lib/cmn/pio.c | 43 ++++++---- qse/lib/net/htrd.c | 30 +++---- qse/lib/net/httpd_task.c | 140 ++++++++++++++++++++++++-------- qse/samples/net/http01.c | 63 +++++++------- 13 files changed, 482 insertions(+), 117 deletions(-) create mode 100644 qse/include/qse/cmn/env.h create mode 100644 qse/lib/cmn/env.c diff --git a/qse/include/qse/cmn/Makefile.am b/qse/include/qse/cmn/Makefile.am index 807352ad..568d3c14 100644 --- a/qse/include/qse/cmn/Makefile.am +++ b/qse/include/qse/cmn/Makefile.am @@ -4,6 +4,7 @@ pkginclude_HEADERS = \ alg.h \ chr.h \ dll.h \ + env.h \ fio.h \ fma.h \ gdl.h \ diff --git a/qse/include/qse/cmn/Makefile.in b/qse/include/qse/cmn/Makefile.in index 449398a7..eb4e070b 100644 --- a/qse/include/qse/cmn/Makefile.in +++ b/qse/include/qse/cmn/Makefile.in @@ -50,9 +50,9 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = -am__pkginclude_HEADERS_DIST = alg.h chr.h dll.h fio.h fma.h gdl.h \ - htb.h lda.h main.h map.h mem.h misc.h oht.h opt.h pio.h pma.h \ - rbt.h rex.h sio.h sll.h stdio.h str.h time.h tio.h xma.h \ +am__pkginclude_HEADERS_DIST = alg.h chr.h dll.h env.h fio.h fma.h \ + gdl.h htb.h lda.h main.h map.h mem.h misc.h oht.h opt.h pio.h \ + pma.h rbt.h rex.h sio.h sll.h stdio.h str.h time.h tio.h xma.h \ Mmgr.hpp StdMmgr.hpp Mmged.hpp am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ @@ -222,9 +222,10 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -pkginclude_HEADERS = alg.h chr.h dll.h fio.h fma.h gdl.h htb.h lda.h \ - main.h map.h mem.h misc.h oht.h opt.h pio.h pma.h rbt.h rex.h \ - sio.h sll.h stdio.h str.h time.h tio.h xma.h $(am__append_1) +pkginclude_HEADERS = alg.h chr.h dll.h env.h fio.h fma.h gdl.h htb.h \ + lda.h main.h map.h mem.h misc.h oht.h opt.h pio.h pma.h rbt.h \ + rex.h sio.h sll.h stdio.h str.h time.h tio.h xma.h \ + $(am__append_1) all: all-am .SUFFIXES: diff --git a/qse/include/qse/cmn/env.h b/qse/include/qse/cmn/env.h new file mode 100644 index 00000000..3a3f1006 --- /dev/null +++ b/qse/include/qse/cmn/env.h @@ -0,0 +1,88 @@ +/* + * $Id: pio.h 455 2011-05-09 16:11:13Z hyunghwan.chung $ + * + 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_CMN_ENV_H_ +#define _QSE_CMN_ENV_H_ + +#include +#include + +typedef struct qse_env_t qse_env_t; + +struct qse_env_t +{ + QSE_DEFINE_COMMON_FIELDS(pio) + + struct + { + qse_size_t capa; + qse_size_t len; + void* ptr; + } buf; + + struct + { + qse_size_t capa; + qse_size_t len; + void** ptr; + } arr; +}; + + +#ifdef __cplusplus +extern "C" { +#endif + +QSE_DEFINE_COMMON_FUNCTIONS(env) + +qse_env_t* qse_env_open ( + qse_mmgr_t* mmgr, + qse_size_t xtnsize +); + +void qse_env_close ( + qse_env_t* env +); + +qse_env_t* qse_env_init ( + qse_env_t* env, + qse_mmgr_t* mmgr +); + +void qse_env_fini ( + qse_env_t* env +); + +/* +void* qse_env_getstring (); +void* qse_env_getarray (); +*/ + +int qse_env_add ( + qse_env_t* env, + const void* name, + const void* value +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/qse/include/qse/cmn/pio.h b/qse/include/qse/cmn/pio.h index 2d8f8abf..9372ba25 100644 --- a/qse/include/qse/cmn/pio.h +++ b/qse/include/qse/cmn/pio.h @@ -1,5 +1,5 @@ /* - * $Id: pio.h 455 2011-05-09 16:11:13Z hyunghwan.chung $ + * $Id: pio.h 533 2011-08-04 15:43:28Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -193,9 +193,9 @@ QSE_DEFINE_COMMON_FUNCTIONS (pio) * @return #qse_pio_t object on success, #QSE_NULL on failure */ qse_pio_t* qse_pio_open ( - qse_mmgr_t* mmgr, /**< memory manager */ - qse_size_t ext, /**< extension size */ - const qse_char_t* cmd, /**< command to execute */ + qse_mmgr_t* mmgr, /**< memory manager */ + qse_size_t ext, /**< extension size */ + const qse_char_t* cmd, /**< command to execute */ int oflags /**< 0 or a number OR'ed of the #qse_pio_oflag_t enumerators*/ ); @@ -292,7 +292,6 @@ qse_ssize_t qse_pio_read ( qse_size_t size, /**< buffer size */ qse_pio_hid_t hid /**< handle ID */ ); -/******/ /** * The qse_pio_write() function writes data. @@ -306,7 +305,6 @@ qse_ssize_t qse_pio_write ( qse_size_t size, /**< data size */ qse_pio_hid_t hid /**< handle ID */ ); -/******/ /** * The qse_pio_flush() flushes buffered data if #QSE_PIO_TEXT has been diff --git a/qse/include/qse/cmn/str.h b/qse/include/qse/cmn/str.h index 9b8d8a9e..50d874e5 100644 --- a/qse/include/qse/cmn/str.h +++ b/qse/include/qse/cmn/str.h @@ -1,5 +1,5 @@ /* - * $Id: str.h 504 2011-07-11 16:31:33Z hyunghwan.chung $ + * $Id: str.h 533 2011-08-04 15:43:28Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -154,8 +154,7 @@ typedef qse_wchar_t* (*qse_wcsxsubst_subst_t) ( (c>=QSE_T('a') && c<=QSE_T('z'))? ((c-QSE_T('a')+10 0) value *= -1; \ -} +} while(0) /* qse_strxtonum (const qse_char_t* nptr, qse_size_t len, qse_char_char** endptr, int base) */ -#define QSE_STRXTONUM(value,nptr,len,endptr,base) \ -{ \ +#define QSE_STRXTONUM(value,nptr,len,endptr,base) do {\ int __ston_f = 0, __ston_v; \ const qse_char_t* __ston_ptr = nptr; \ const qse_char_t* __ston_end = __ston_ptr + len; \ @@ -193,9 +191,105 @@ typedef qse_wchar_t* (*qse_wcsxsubst_subst_t) ( (__ston_v = QSE_CHARTONUM(*__ston_ptr, base)) != base; __ston_ptr++) { \ value = value * base + __ston_v; \ } \ - if (endptr != QSE_NULL) *((const qse_char_t**)endptr) = __ston_ptr; \ + if (endptr) *((const qse_char_t**)endptr) = __ston_ptr; \ if (__ston_f > 0) value *= -1; \ -} +} while(0) + +/* int qse_mchartonum (qse_mchar_t c, int base) */ +#define QSE_MCHARTONUM(c,base) \ + ((c>=QSE_MT('0') && c<=QSE_MT('9'))? ((c-QSE_MT('0')=QSE_MT('A') && c<=QSE_MT('Z'))? ((c-QSE_MT('A')+10=QSE_MT('a') && c<=QSE_MT('z'))? ((c-QSE_MT('a')+10 0) value *= -1; \ +} while(0) + +/* qse_strxtonum (const qse_mchar_t* nptr, qse_size_t len, qse_mchar_t** endptr, int base) */ +#define QSE_MSTRXTONUM(value,nptr,len,endptr,base) do {\ + int __ston_f = 0, __ston_v; \ + const qse_mchar_t* __ston_ptr = nptr; \ + const qse_mchar_t* __ston_end = __ston_ptr + len; \ + value = 0; \ + while (__ston_ptr < __ston_end) { \ + qse_mchar_t __ston_c = *__ston_ptr; \ + if (__ston_c == QSE_MT(' ') || __ston_c == QSE_MT('\t')) { \ + __ston_ptr++; continue; \ + } \ + if (__ston_c == QSE_MT('-')) { __ston_f++; __ston_ptr++; } \ + if (__ston_c == QSE_MT('+')) { __ston_ptr++; } \ + break; \ + } \ + for (value = 0; __ston_ptr < __ston_end && \ + (__ston_v = QSE_MCHARTONUM(*__ston_ptr, base)) != base; __ston_ptr++) { \ + value = value * base + __ston_v; \ + } \ + if (endptr) *((const qse_mchar_t**)endptr) = __ston_ptr; \ + if (__ston_f > 0) value *= -1; \ +} while(0) + +/* int qse_wchartonum (qse_wchar_t c, int base) */ +#define QSE_WCHARTONUM(c,base) \ + ((c>=QSE_WT('0') && c<=QSE_WT('9'))? ((c-QSE_WT('0')=QSE_WT('A') && c<=QSE_WT('Z'))? ((c-QSE_WT('A')+10=QSE_WT('a') && c<=QSE_WT('z'))? ((c-QSE_WT('a')+10 0) value *= -1; \ +} while(0) + +/* qse_strxtonum (const qse_wchar_t* nptr, qse_size_t len, qse_wchar_t** endptr, int base) */ +#define QSE_WSTRXTONUM(value,nptr,len,endptr,base) do {\ + int __ston_f = 0, __ston_v; \ + const qse_wchar_t* __ston_ptr = nptr; \ + const qse_wchar_t* __ston_end = __ston_ptr + len; \ + value = 0; \ + while (__ston_ptr < __ston_end) { \ + qse_wchar_t __ston_c = *__ston_ptr; \ + if (__ston_c == QSE_WT(' ') || __ston_c == QSE_WT('\t')) { \ + __ston_ptr++; continue; \ + } \ + if (__ston_c == QSE_WT('-')) { __ston_f++; __ston_ptr++; } \ + if (__ston_c == QSE_WT('+')) { __ston_ptr++; } \ + break; \ + } \ + for (value = 0; __ston_ptr < __ston_end && \ + (__ston_v = QSE_WCHARTONUM(*__ston_ptr, base)) != base; __ston_ptr++) { \ + value = value * base + __ston_v; \ + } \ + if (endptr) *((const qse_wchar_t**)endptr) = __ston_ptr; \ + if (__ston_f > 0) value *= -1; \ +} while(0) /** * The qse_mbstrmx_op_t defines a string trimming operation. diff --git a/qse/include/qse/net/httpd.h b/qse/include/qse/net/httpd.h index c86eb6ab..8ccf495d 100644 --- a/qse/include/qse/net/httpd.h +++ b/qse/include/qse/net/httpd.h @@ -213,7 +213,8 @@ qse_httpd_task_t* qse_httpd_entaskcgi ( qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_httpd_task_t* pred, - const qse_char_t* path + const qse_char_t* path, + const qse_http_version_t* version ); void* qse_httpd_allocmem ( diff --git a/qse/lib/cmn/Makefile.am b/qse/lib/cmn/Makefile.am index 078b2e23..38e87d12 100644 --- a/qse/lib/cmn/Makefile.am +++ b/qse/lib/cmn/Makefile.am @@ -19,6 +19,7 @@ libqsecmn_la_SOURCES = \ fio.c pio.c sio.c \ alg_search.c \ alg_sort.c \ + env.c \ time.c \ misc.c \ assert.c \ diff --git a/qse/lib/cmn/Makefile.in b/qse/lib/cmn/Makefile.in index 8caccda8..8d24a4ba 100644 --- a/qse/lib/cmn/Makefile.in +++ b/qse/lib/cmn/Makefile.in @@ -81,7 +81,7 @@ am_libqsecmn_la_OBJECTS = mem.lo xma.lo fma.lo pma.lo chr.lo \ str_subst.lo str_tok.lo str_trm.lo str_word.lo lda.lo oht.lo \ htb.lo rbt.lo sll.lo gdl.lo dll.lo opt.lo tio.lo tio_get.lo \ tio_put.lo fio.lo pio.lo sio.lo alg_search.lo alg_sort.lo \ - time.lo misc.lo assert.lo main.lo stdio.lo + env.lo time.lo misc.lo assert.lo main.lo stdio.lo libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS) libqsecmn_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ @@ -283,6 +283,7 @@ libqsecmn_la_SOURCES = \ fio.c pio.c sio.c \ alg_search.c \ alg_sort.c \ + env.c \ time.c \ misc.c \ assert.c \ @@ -379,6 +380,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chr_cnv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dll.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/env.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fio.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fma.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdl.Plo@am__quote@ diff --git a/qse/lib/cmn/env.c b/qse/lib/cmn/env.c new file mode 100644 index 00000000..93d088ac --- /dev/null +++ b/qse/lib/cmn/env.c @@ -0,0 +1,91 @@ +/* + * $Id: pio.h 455 2011-05-09 16:11:13Z hyunghwan.chung $ + * + 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 "mem.h" + +QSE_IMPLEMENT_COMMON_FUNCTIONS(env) + +qse_env_t* qse_env_open (qse_mmgr_t* mmgr, qse_size_t xtnsize) +{ + qse_env_t* env; + + if (mmgr == QSE_NULL) + { + mmgr = QSE_MMGR_GETDFL(); + + QSE_ASSERTX (mmgr != QSE_NULL, + "Set the memory manager with QSE_MMGR_SETDFL()"); + + if (mmgr == QSE_NULL) return QSE_NULL; + } + + env = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_env_t) + xtnsize); + if (env == QSE_NULL) return QSE_NULL; + + if (qse_env_init (env, mmgr) == QSE_NULL) + { + QSE_MMGR_FREE (mmgr, env); + return QSE_NULL; + } + + return env; +} + +void qse_env_close (qse_env_t* env) +{ + qse_env_fini (env); + QSE_MMGR_FREE (env->mmgr, env); +} + +qse_env_t* qse_env_init (qse_env_t* env, qse_mmgr_t* mmgr) +{ + QSE_MEMSET (env, 0, QSE_SIZEOF(*env)); + return env; +} + +void qse_env_fini (qse_env_t* env) +{ + if (env->arr.ptr) QSE_MMGR_FREE (env->mmgr, env->arr.ptr); + if (env->buf.ptr) QSE_MMGR_FREE (env->mmgr, env->buf.ptr); +} + + +static int expand_buffer (qse_env_t* env) +{ + if (env->buf.ptr == QSE_NULL) + { + } + return -1; +} + +static int expand_array (qse_env_t* env) +{ + if (env->arr.ptr == QSE_NULL) + { + } + return -1; +} + +int qse_env_add (qse_env_t* env, const void* name, const void* value) +{ + return -1; +} diff --git a/qse/lib/cmn/pio.c b/qse/lib/cmn/pio.c index cde728ed..f7f33779 100644 --- a/qse/lib/cmn/pio.c +++ b/qse/lib/cmn/pio.c @@ -1,5 +1,5 @@ /* - * $Id: pio.c 455 2011-05-09 16:11:13Z hyunghwan.chung $ + * $Id: pio.c 533 2011-08-04 15:43:28Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -44,7 +44,8 @@ static qse_ssize_t pio_input (int cmd, void* arg, void* buf, qse_size_t size); static qse_ssize_t pio_output (int cmd, void* arg, void* buf, qse_size_t size); qse_pio_t* qse_pio_open ( - qse_mmgr_t* mmgr, qse_size_t ext, const qse_char_t* path, int oflags) + qse_mmgr_t* mmgr, qse_size_t ext, + const qse_char_t* cmd, int oflags) { qse_pio_t* pio; @@ -61,7 +62,7 @@ qse_pio_t* qse_pio_open ( pio = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_pio_t) + ext); if (pio == QSE_NULL) return QSE_NULL; - if (qse_pio_init (pio, mmgr, path, oflags) == QSE_NULL) + if (qse_pio_init (pio, mmgr, cmd, oflags) == QSE_NULL) { QSE_MMGR_FREE (mmgr, pio); return QSE_NULL; @@ -120,8 +121,8 @@ qse_pio_t* qse_pio_init ( HFILE os2devnul = (HFILE)-1; #elif defined(__DOS__) - /* TODO: implmenet this for dos - unsupported yet */ + + /* DOS not multi-processed. can't support pio */ #else qse_pio_pid_t pid; @@ -264,7 +265,11 @@ qse_pio_t* qse_pio_init ( NULL, /* LPSECURITY_ATTRIBUTES lpProcessAttributes */ NULL, /* LPSECURITY_ATTRIBUTES lpThreadAttributes */ TRUE, /* BOOL bInheritHandles */ +#ifdef QSE_CHAR_IS_MCHAR 0, /* DWORD dwCreationFlags */ +#else + CREATE_UNICODE_ENVIRONMENT, /* DWORD dwCreationFlags */ +#endif NULL, /* LPVOID lpEnvironment */ NULL, /* LPCTSTR lpCurrentDirectory */ &startup, /* LPSTARTUPINFO lpStartupInfo */ @@ -533,7 +538,8 @@ qse_pio_t* qse_pio_init ( #elif defined(__DOS__) - /* TODO: implement this */ + /* DOS not multi-processed. can't support pio */ + return QSE_NULL; #else @@ -650,9 +656,9 @@ qse_pio_t* qse_pio_init ( (oflags & QSE_PIO_ERRTONUL)) { #ifdef O_LARGEFILE - devnull = QSE_OPEN ("/dev/null", O_RDWR|O_LARGEFILE, 0); + devnull = QSE_OPEN (QSE_MT("/dev/null"), O_RDWR|O_LARGEFILE, 0); #else - devnull = QSE_OPEN ("/dev/null", O_RDWR, 0); + devnull = QSE_OPEN (QSE_MT("/dev/null"), O_RDWR, 0); #endif if (devnull <= -1) goto child_oops; } @@ -784,6 +790,9 @@ qse_pio_t* qse_pio_init ( argv[i] = QSE_NULL; QSE_EXECVE (argv[0], argv, environ); + + /* this won't be reached if execve succeeds */ + QSE_MMGR_FREE (pio->mmgr, argv); } child_oops: @@ -801,7 +810,8 @@ qse_pio_t* qse_pio_init ( * X * WRITE => 1 */ - QSE_CLOSE (handle[0]); handle[0] = QSE_PIO_HND_NIL; + QSE_CLOSE (handle[0]); + handle[0] = QSE_PIO_HND_NIL; } if (oflags & QSE_PIO_READOUT) @@ -812,7 +822,8 @@ qse_pio_t* qse_pio_init ( * X * READ => 2 */ - QSE_CLOSE (handle[3]); handle[3] = QSE_PIO_HND_NIL; + QSE_CLOSE (handle[3]); + handle[3] = QSE_PIO_HND_NIL; } if (oflags & QSE_PIO_READERR) @@ -823,7 +834,8 @@ qse_pio_t* qse_pio_init ( * X * READ => 4 */ - QSE_CLOSE (handle[5]); handle[5] = QSE_PIO_HND_NIL; + QSE_CLOSE (handle[5]); + handle[5] = QSE_PIO_HND_NIL; } #endif @@ -888,7 +900,7 @@ oops: for (i = 0; i < QSE_COUNTOF(tio); i++) { - if (tio[i] != QSE_NULL) qse_tio_close (tio[i]); + if (tio[i]) qse_tio_close (tio[i]); } #if defined(_WIN32) @@ -899,10 +911,9 @@ oops: if (handle[i] != QSE_PIO_HND_NIL) DosClose (handle[i]); } #elif defined(__DOS__) - for (i = minidx; i < maxidx; i++) - { - if (handle[i] != QSE_PIO_HND_NIL) close (handle[i]); - } + + /* DOS not multi-processed. can't support pio */ + #else for (i = minidx; i < maxidx; i++) { diff --git a/qse/lib/net/htrd.c b/qse/lib/net/htrd.c index 06c62e28..7602a726 100644 --- a/qse/lib/net/htrd.c +++ b/qse/lib/net/htrd.c @@ -243,7 +243,7 @@ static qse_mchar_t* parse_initial_line ( { int n, status; - if (*p == '/' && p[1] != '\0' && p[2] == '.') + if (*p == QSE_MT('/') && p[1] != QSE_MT('\0') && p[2] == QSE_MT('.')) { int q = digit_to_num(p[1]); int w = digit_to_num(p[3]); @@ -274,18 +274,20 @@ static qse_mchar_t* parse_initial_line ( } while ((n = digit_to_num(*p)) >= 0); - /* status code must be followed by space */ - if (!is_space_octet(*p)) goto badre; - qse_htre_setsstatus (&htrd->re, status); + /* i don't treat the following weird messages as bad message + * no status message follows the status code + * no space between the status code and the status message + */ + /* skip spaces */ - do p++; while (is_space_octet(*p)); - + while (is_space_octet(*p)) p++; + tmp.ptr = p; - while (*p != '\0' && *p != '\n') p++; + while (*p != QSE_MT('\0') && *p != QSE_MT('\n')) p++; tmp.len = p - tmp.ptr; - + if (qse_htre_setsmessagefromcstr (&htrd->re, &tmp) <= -1) goto outofmem; /* adjust Connection: close for HTTP 1.0 or eariler */ @@ -311,9 +313,9 @@ static qse_mchar_t* parse_initial_line ( param.ptr = QSE_NULL; out = p; - while (*p != '\0' && !is_space_octet(*p)) + while (*p != QSE_MT('\0') && !is_space_octet(*p)) { - if (*p == '%' && param.ptr == QSE_NULL) + if (*p == QSE_MT('%') && param.ptr == QSE_NULL) { /* decode percence-encoded charaters in the * path part. if we're in the parameter string @@ -336,14 +338,14 @@ static qse_mchar_t* parse_initial_line ( } else *out++ = *p++; } - else if (*p == '?') + else if (*p == QSE_MT('?')) { if (!param.ptr) { /* ? must be explicit to be a argument instroducer. * %3f is just a literal. */ tmp.len = out - tmp.ptr; - *out++ = '\0'; /* null-terminate the path part */ + *out++ = QSE_MT('\0'); /* null-terminate the path part */ param.ptr = out; p++; } @@ -356,7 +358,7 @@ static qse_mchar_t* parse_initial_line ( if (!is_space_octet(*p)) goto badre; /* null-terminate the url part though we know the length */ - *out = '\0'; + *out = QSE_MT('\0'); if (param.ptr) { @@ -370,7 +372,7 @@ static qse_mchar_t* parse_initial_line ( /* skip spaces after the url part */ do { p++; } while (is_space_octet(*p)); - /* check htrd version */ + /* check protocol version */ if ((p[0] == 'H' || p[0] == 'h') && (p[1] == 'T' || p[1] == 't') && (p[2] == 'T' || p[2] == 't') && diff --git a/qse/lib/net/httpd_task.c b/qse/lib/net/httpd_task.c index 1f50c235..115cd198 100644 --- a/qse/lib/net/httpd_task.c +++ b/qse/lib/net/httpd_task.c @@ -21,6 +21,7 @@ #include "httpd.h" #include "../cmn/mem.h" #include +#include #include #include @@ -661,23 +662,39 @@ qse_httpd_task_t* qse_httpd_entaskpath ( /*------------------------------------------------------------------------*/ +typedef struct task_cgi_arg_t task_cgi_arg_t; +struct task_cgi_arg_t +{ + const qse_char_t* path; + qse_http_version_t version; +}; + typedef struct task_cgi_t task_cgi_t; struct task_cgi_t { const qse_char_t* path; - - qse_htrd_t* htrd; - - qse_mbs_t* res; - qse_mchar_t* res_ptr; - qse_size_t res_left; - int chunked; - int sent; + qse_http_version_t version; qse_pio_t* pio; + qse_htrd_t* htrd; + + qse_mbs_t* res; + qse_mchar_t* res_ptr; + qse_size_t res_left; + + /* if true, close connection after response is sent out */ + int disconnect; + /* if true, the content of response is chunked */ + int content_chunked; + /* if true, content_length is set. */ + int content_length_set; + /* content-length that CGI returned */ + qse_size_t content_length; + /* the number of octets in the contents received */ + qse_size_t content_received; qse_mchar_t buf[MAX_SEND_SIZE]; - qse_size_t buflen; + qse_size_t buflen; }; typedef struct cgi_htrd_xtn_t cgi_htrd_xtn_t; @@ -706,6 +723,7 @@ static int cgi_htrd_handle_request (qse_htrd_t* htrd, qse_htre_t* req) cgi_htrd_xtn_t* xtn = (cgi_htrd_xtn_t*) qse_htrd_getxtn (htrd); task_cgi_t* cgi = xtn->cgi; const qse_mchar_t* status; + static qse_http_version_t v11 = { 1, 1 }; QSE_ASSERT (req->attr.hurried); @@ -713,13 +731,28 @@ static int cgi_htrd_handle_request (qse_htrd_t* htrd, qse_htre_t* req) if (status) { qse_mchar_t buf[128]; - snprintf (buf, QSE_COUNTOF(buf), - QSE_MT("HTTP/%d.%d "), - 1,1 /* TODO: get the version from outer request....... */ - ); - if (qse_mbs_cat (cgi->res, buf) == (qse_size_t)-1) return -1; + int nstatus; + qse_mchar_t* endptr; + /* TODO: check the syntax of status value??? */ - if (qse_mbs_cat (cgi->res, status) == (qse_size_t)-1) return -1; + + QSE_MSTRTONUM (nstatus,status,&endptr,10); + + snprintf (buf, QSE_COUNTOF(buf), + QSE_MT("HTTP/%d.%d %d "), + cgi->version.major, + cgi->version.minor, + nstatus + ); + + /* + Would it need this kind of extra work? + while (QSE_ISMSPACE(*endptr)) endptr++; + if (*endptr == QSE_MT('\0')) .... + */ + + if (qse_mbs_cat (cgi->res, buf) == (qse_size_t)-1) return -1; + if (qse_mbs_cat (cgi->res, endptr) == (qse_size_t)-1) return -1; if (qse_mbs_cat (cgi->res, QSE_MT("\r\n")) == (qse_size_t)-1) return -1; } else @@ -727,16 +760,25 @@ static int cgi_htrd_handle_request (qse_htrd_t* htrd, qse_htre_t* req) qse_mchar_t buf[128]; snprintf (buf, QSE_COUNTOF(buf), QSE_MT("HTTP/%d.%d 200 OK\r\n"), - 1,1 /* TODO: get the version from outer request....... */ + cgi->version.major, cgi->version.minor ); if (qse_mbs_cat (cgi->res, buf) == (qse_size_t)-1) return -1; } - if (!req->attr.content_length_set) cgi->chunked = 1; + if (req->attr.content_length_set) + { + cgi->content_length_set = 1; + cgi->content_length = req->attr.content_length; + } + else + { + /* no Content-Length returned by CGI */ + if (qse_comparehttpversions (&cgi->version, &v11) >= 0) + cgi->content_chunked = 1; + else cgi->disconnect = 1; + } -qse_printf (QSE_T("req->attr.content_length_set = %d, req->attr.content_length = %d\n"), (int)req->attr.content_length_set, req->attr.content_length); - - if (cgi->chunked) + if (cgi->content_chunked) { if (qse_mbs_cat (cgi->res, QSE_MT("Transfer-Encoding: chunked\r\n")) == (qse_size_t)-1) return -1; } @@ -744,18 +786,26 @@ qse_printf (QSE_T("req->attr.content_length_set = %d, req->attr.content_length = if (qse_htre_walkheaders (req, walk_cgi_headers, cgi) <= -1) return -1; if (qse_mbs_ncat (cgi->res, QSE_MT("\r\n"), 2) == (qse_size_t)-1) return -1; - if (qse_htre_getcontentlen(req) > 0) + cgi->content_received = qse_htre_getcontentlen(req); + if (cgi->content_length_set && + cgi->content_received > cgi->content_length) { - if (cgi->chunked) +/* TODO: cgi returning too much data... something is wrong in CGI */ + return -1; + } + + if (cgi->content_received > 0) + { + if (cgi->content_chunked) { qse_mchar_t buf[64]; - snprintf (buf, QSE_COUNTOF(buf), QSE_MT("%lX\r\n"), (unsigned long)qse_htre_getcontentlen(req)); + snprintf (buf, QSE_COUNTOF(buf), QSE_MT("%lX\r\n"), (unsigned long)cgi->content_received); if (qse_mbs_cat (cgi->res, buf) == (qse_size_t)-1) return -1; } if (qse_mbs_ncat (cgi->res, qse_htre_getcontentptr(req), qse_htre_getcontentlen(req)) == (qse_size_t)-1) return -1; - if (cgi->chunked) + if (cgi->content_chunked) { if (qse_mbs_ncat (cgi->res, QSE_MT("\r\n"), 2) == (qse_size_t)-1) return -1; } @@ -775,9 +825,12 @@ static int task_init_cgi ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) { task_cgi_t* xtn = (task_cgi_t*)qse_httpd_gettaskxtn (httpd, task); + task_cgi_arg_t* arg = (task_cgi_arg_t*)task->ctx; + QSE_MEMSET (xtn, 0, QSE_SIZEOF(*xtn)); - qse_strcpy ((qse_char_t*)(xtn + 1), task->ctx); + qse_strcpy ((qse_char_t*)(xtn + 1), arg->path); xtn->path = (qse_char_t*)(xtn + 1); + xtn->version = arg->version; task->ctx = xtn; return 0; } @@ -831,11 +884,12 @@ static int task_main_cgi_4 ( qse_printf (QSE_T("task_main_cgi_4\n")); - if (cgi->chunked) + if (cgi->content_chunked) { qse_size_t count, extra; qse_mchar_t chunklen[7]; +qse_printf (QSE_T("READING CHUNKED MODE...\n")); extra = (QSE_SIZEOF(chunklen) - 1) + 2; count = QSE_SIZEOF(cgi->buf) - cgi->buflen; if (count > extra) @@ -876,6 +930,8 @@ qse_printf (QSE_T("task_main_cgi_4\n")); /* set the trailing CR & LF for a chunk */ cgi->buf[cgi->buflen++] = QSE_MT('\r'); cgi->buf[cgi->buflen++] = QSE_MT('\n'); + + cgi->content_received += n; } } else @@ -900,6 +956,15 @@ qse_printf (QSE_T("READING IN NON-CHUNKED MODE...\n")); } cgi->buflen += n; + cgi->content_received += n; + } + + if (cgi->content_length_set && + cgi->content_received > cgi->content_length) + { +/* TODO: cgi returning too much data... something is wrong in CGI */ +qse_printf (QSE_T("CGI FUCKED UP...RETURNING TOO MUCH DATA\n")); + return -1; } n = send (client->handle.i, cgi->buf, cgi->buflen, 0); @@ -909,8 +974,6 @@ qse_printf (QSE_T("READING IN NON-CHUNKED MODE...\n")); /* TODO: logging ... */ return -1; } -cgi->sent += n; -qse_printf (QSE_T("READING IN NON-CHUNKED MODE...SENT %d so far\n"), cgi->sent); QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n); cgi->buflen -= n; @@ -991,7 +1054,6 @@ qse_printf (QSE_T("[cgi_2 ]\n")); cgi->buflen += n; -qse_printf (QSE_T("[feeding ]\n")); if (qse_htrd_feed (cgi->htrd, cgi->buf, cgi->buflen) <= -1) { /* TODO: logging */ @@ -1002,7 +1064,14 @@ qse_printf (QSE_T("[feeding ]\n")); if (QSE_MBS_LEN(cgi->res) > 0) { - /* the headers and probably some contents are ready */ + /* the htrd handler composed some response. + * this means that at least it finished processing CGI headers. + * some contents could be in cgi->res, though. + */ + + if (cgi->disconnect && + qse_httpd_entaskdisconnect (httpd, client, task) == QSE_NULL) return -1; + cgi->res_ptr = QSE_MBS_PTR(cgi->res); cgi->res_left = QSE_MBS_LEN(cgi->res); @@ -1046,7 +1115,7 @@ qse_printf (QSE_T("internal server error....\n")); } qse_printf (QSE_T("[pio open for %s]\n"), cgi->path); - cgi->pio = qse_pio_open (httpd->mmgr, 0, cgi->path, QSE_PIO_READOUT | QSE_PIO_WRITEIN); + cgi->pio = qse_pio_open (httpd->mmgr, 0, cgi->path, QSE_PIO_READOUT | QSE_PIO_WRITEIN | QSE_PIO_ERRTONUL); if (cgi->pio == QSE_NULL) { /* TODO: entask internal server errror */ @@ -1068,15 +1137,20 @@ qse_httpd_task_t* qse_httpd_entaskcgi ( qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_httpd_task_t* pred, - const qse_char_t* path) + const qse_char_t* path, + const qse_http_version_t* version) { qse_httpd_task_t task; + task_cgi_arg_t arg; + + arg.path = path; + arg.version = *version; QSE_MEMSET (&task, 0, QSE_SIZEOF(task)); task.init = task_init_cgi; task.fini = task_fini_cgi; task.main = task_main_cgi; - task.ctx = (void*)path; + task.ctx = &arg; return qse_httpd_entask ( httpd, client, pred, &task, diff --git a/qse/samples/net/http01.c b/qse/samples/net/http01.c index fb9a6cf1..f98c3d53 100644 --- a/qse/samples/net/http01.c +++ b/qse/samples/net/http01.c @@ -61,41 +61,42 @@ qse_printf (QSE_T("content = [%.*S]\n"), if (dot && qse_mbscmp (dot, QSE_MT(".cgi")) == 0) { - static qse_http_version_t v1 = { 1, 0 }; - /* persistent connection and cgi not compatible */ - if (qse_comparehttpversions (qse_htre_getversion(req), &v1) <= 0) - req->attr.connection_close = 1; - -qse_httpd_entaskcgi (httpd, client, QSE_NULL, QSE_T("/tmp/test.cgi")); - goto done; - } - - rangestr = qse_htre_getheaderval (req, "Range"); - if (rangestr && qse_parsehttprange (rangestr, &range) <= -1) - { -#if 0 -qse_httpd_entaskstatictext (httpd, client, QSE_NULL, QSE_MT("HTTP/1.1 416 Requested range not satisfiable\r\nContent-Length: 5\r\n\r\nA\r\n\r\n")); -#endif - - const qse_mchar_t* msg; - msg = QSE_MT("Requested range not satisfiableREQUESTED RANGE NOT SATISFIABLE"); - x = qse_httpd_entaskformat ( - httpd, client, QSE_NULL, - QSE_MT("HTTP/%d.%d 416 Requested range not satisfiable\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"), - req->version.major, req->version.minor, - (int)qse_mbslen(msg) + 4, msg - ); + /* cgi */ + x = qse_httpd_entaskcgi (httpd, client, QSE_NULL, QSE_T("/tmp/test.cgi"), qse_htre_getversion(req)); if (x == QSE_NULL) goto oops; + +#if 0 + x = qse_httpd_entasknphcgi (httpd, client, QSE_NULL, QSE_T("/tmp/test.cgi"), qse_htre_getversion(req)); +#endif } else { - x = qse_httpd_entaskpath ( - httpd, client, QSE_NULL, - qse_htre_getqpathptr(req), - (rangestr? &range: QSE_NULL), - qse_htre_getversion(req) - ); - if (x == QSE_NULL) goto oops; + rangestr = qse_htre_getheaderval (req, "Range"); + if (rangestr && qse_parsehttprange (rangestr, &range) <= -1) + { +#if 0 +qse_httpd_entaskstatictext (httpd, client, QSE_NULL, QSE_MT("HTTP/1.1 416 Requested range not satisfiable\r\nContent-Length: 5\r\n\r\nA\r\n\r\n")); +#endif + const qse_mchar_t* msg; + msg = QSE_MT("Requested range not satisfiableREQUESTED RANGE NOT SATISFIABLE"); + x = qse_httpd_entaskformat ( + httpd, client, QSE_NULL, + QSE_MT("HTTP/%d.%d 416 Requested range not satisfiable\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"), + req->version.major, req->version.minor, + (int)qse_mbslen(msg) + 4, msg + ); + if (x == QSE_NULL) goto oops; + } + else + { + x = qse_httpd_entaskpath ( + httpd, client, QSE_NULL, + qse_htre_getqpathptr(req), + (rangestr? &range: QSE_NULL), + qse_htre_getversion(req) + ); + if (x == QSE_NULL) goto oops; + } } } else