written more http code
This commit is contained in:
parent
afbbdd03ea
commit
ec02be14e5
@ -1,4 +1,4 @@
|
||||
pkgincludedir= $(includedir)/qse/net
|
||||
pkginclude_HEADERS = htre.h htrd.h http.h
|
||||
pkginclude_HEADERS = http.h htre.h htrd.h httpd.h
|
||||
|
||||
|
||||
|
@ -213,7 +213,7 @@ target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
pkginclude_HEADERS = htre.h htrd.h http.h
|
||||
pkginclude_HEADERS = http.h htre.h htrd.h httpd.h
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
|
@ -32,11 +32,9 @@ enum qse_htrd_errnum_t
|
||||
QSE_HTRD_ENOMEM,
|
||||
|
||||
QSE_HTRD_EDISCON,
|
||||
QSE_HTRD_EREADER,
|
||||
|
||||
QSE_HTRD_EBADRE,
|
||||
QSE_HTRD_EBADHDR,
|
||||
QSE_HTRD_EREQCBS
|
||||
QSE_HTRD_ERECBS
|
||||
};
|
||||
|
||||
typedef enum qse_htrd_errnum_t qse_htrd_errnum_t;
|
||||
@ -58,6 +56,8 @@ struct qse_htrd_recbs_t
|
||||
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);
|
||||
|
||||
int (*qparamstr) (qse_htrd_t* htrd, const qse_mcstr_t* key, const qse_mcstr_t* val);
|
||||
};
|
||||
|
||||
struct qse_htrd_t
|
||||
@ -96,11 +96,19 @@ struct qse_htrd_t
|
||||
void* chl;
|
||||
} fed;
|
||||
|
||||
struct
|
||||
{
|
||||
/* temporary space to store a key and value pair
|
||||
* during the call to qse_http_scanqparamstr() */
|
||||
qse_htob_t qparam;
|
||||
} tmp;
|
||||
|
||||
enum
|
||||
{
|
||||
QSE_HTRD_RETYPE_Q,
|
||||
QSE_HTRD_RETYPE_S
|
||||
} retype;
|
||||
|
||||
qse_htre_t re;
|
||||
|
||||
qse_htoc_t rbuf[4096];
|
||||
@ -172,6 +180,11 @@ int qse_htrd_read (
|
||||
qse_htrd_t* htrd /**< htrd */
|
||||
);
|
||||
|
||||
int qse_htrd_scanqparam (
|
||||
qse_htrd_t* http,
|
||||
const qse_mcstr_t* cstr
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -36,7 +36,7 @@ struct qse_htre_t
|
||||
|
||||
int qmethod_or_sstatus;
|
||||
qse_htob_t qpath_or_smesg;
|
||||
qse_htob_t qparamstr;
|
||||
qse_htob_t qparam;
|
||||
|
||||
/* special attributes derived from the header */
|
||||
struct
|
||||
@ -68,20 +68,49 @@ struct qse_htre_t
|
||||
#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_getqpath(re) (&(re)->qpath_or_smesg)
|
||||
#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_getqpath(re) (&(re)->qpath_or_smesg)
|
||||
#define qse_htre_getqpathxstr(re) QSE_MBS_XSTR(&(re)->qpath_or_smesg)
|
||||
#define qse_htre_getqpathcstr(re) QSE_MBS_CSTR(&(re)->qpath_or_smesg)
|
||||
#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_getqparamstr(re) (&(re)->qparamstr)
|
||||
#define qse_htre_getqparamstrptr(re) QSE_MBS_PTR(&(re)->qparamstr)
|
||||
#define qse_htre_getqparamstrlen(re) QSE_MBS_LEN(&(re)->qparamstr)
|
||||
#define qse_htre_getqparam(re) (&(re)->qparam)
|
||||
#define qse_htre_getqparamxstr(re) QSE_MBS_XSTR(&(re)->qparam)
|
||||
#define qse_htre_getqparamcstr(re) QSE_MBS_CSTR(&(re)->qparam)
|
||||
#define qse_htre_getqparamptr(re) QSE_MBS_PTR(&(re)->qparam)
|
||||
#define qse_htre_getqparamlen(re) QSE_MBS_LEN(&(re)->qparam)
|
||||
|
||||
#define qse_htre_getsmessage(re) (&(re)->qpath_or_smesg)
|
||||
#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_getsmessage(re) (&(re)->qpath_or_smesg)
|
||||
#define qse_htre_getsmessagexstr(re) QSE_MBS_XSTR(&(re)->qpath_or_smesg)
|
||||
#define qse_htre_getsmessagecstr(re) QSE_MBS_CSTR(&(re)->qpath_or_smesg)
|
||||
#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_setqpath(re,v) qse_htre_setbuf((re),qse_htre_getqpath(re),(v))
|
||||
#define qse_htre_setsmessage(re,v) qse_htre_setbuf((re),qse_htre_getsmessage(re),(v))
|
||||
#define qse_htre_getcontent(re) (&(re)->content)
|
||||
#define qse_htre_getcontentxstr(re) QSE_MBS_XSTR(&(re)->content)
|
||||
#define qse_htre_getcontentcstr(re) QSE_MBS_CSTR(&(re)->content)
|
||||
#define qse_htre_getcontentptr(re) QSE_MBS_PTR(&(re)->content)
|
||||
#define qse_htre_getcontentlen(re) QSE_MBS_LEN(&(re)->content)
|
||||
|
||||
#define qse_htre_setqpathfromcstr(re,v) \
|
||||
qse_htre_setstrfromcstr((re),qse_htre_getqpath(re),(v))
|
||||
#define qse_htre_setqpathfromxstr(re,v) \
|
||||
qse_htre_setstrfromxstr((re),qse_htre_getqpath(re),(v))
|
||||
|
||||
#define qse_htre_setqparamfromcstr(re,v) \
|
||||
qse_htre_setstrfromcstr((re),qse_htre_getqparam(re),(v))
|
||||
#define qse_htre_setqparamfromxstr(re,v) \
|
||||
qse_htre_setstrfromxstr((re),qse_htre_getqparam(re),(v))
|
||||
|
||||
#define qse_htre_setsmessagefromcstr(re,v) \
|
||||
qse_htre_setstrfromcstr((re),qse_htre_getsmessage(re),(v))
|
||||
#define qse_htre_setsmessagefromxstr(re,v) \
|
||||
qse_htre_setstrfromxstr((re),qse_htre_getsmessage(re),(v))
|
||||
|
||||
#define qse_htre_setcontentfromcstr(re,v) \
|
||||
qse_htre_setstrfromcstr((re),qse_htre_getcontent(re),(v))
|
||||
#define qse_htre_setcontentfromxstr(re,v) \
|
||||
qse_htre_setstrfromxstr((re),qse_htre_getcontent(re),(v))
|
||||
|
||||
#define qse_htre_setdiscard(re,v) QSE_BLOCK((re)->discard = (v);)
|
||||
|
||||
@ -102,21 +131,16 @@ void qse_htre_clear (
|
||||
qse_htre_t* re
|
||||
);
|
||||
|
||||
int qse_htre_setbuf (
|
||||
qse_htre_t* re,
|
||||
qse_htob_t* buf,
|
||||
const qse_mcstr_t* str
|
||||
int qse_htre_setstrfromcstr (
|
||||
qse_htre_t* re,
|
||||
qse_htob_t* str,
|
||||
const qse_mcstr_t* cstr
|
||||
);
|
||||
|
||||
void qse_htre_getbuf (
|
||||
qse_htre_t* re,
|
||||
const qse_htob_t* buf,
|
||||
qse_mcstr_t* str
|
||||
);
|
||||
|
||||
int qse_htre_setqparamstr (
|
||||
qse_htre_t* re,
|
||||
const qse_mcstr_t* str
|
||||
int qse_htre_setstrfromxstr (
|
||||
qse_htre_t* re,
|
||||
qse_htob_t* str,
|
||||
const qse_mxstr_t* xstr
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <qse/macros.h>
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/htb.h>
|
||||
#include <qse/cmn/time.h>
|
||||
|
||||
/*typedef qse_byte_t qse_htoc_t;*/
|
||||
typedef qse_mchar_t qse_htoc_t;
|
||||
@ -56,12 +57,6 @@ enum qse_http_method_t
|
||||
|
||||
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
|
||||
@ -80,10 +75,14 @@ int qse_gethttpmethodtypefromstr (
|
||||
qse_http_method_t* type
|
||||
);
|
||||
|
||||
int qse_scanhttpparamstr (
|
||||
const qse_htoc_t* paramstr,
|
||||
qse_scanhttpparamstr_callback_t callback,
|
||||
void* ctx
|
||||
int qse_gethttpdatetime (
|
||||
const qse_htoc_t* str,
|
||||
qse_ntime_t* t
|
||||
);
|
||||
|
||||
int qse_gethttpdatetimefromstr (
|
||||
const qse_mcstr_t* str,
|
||||
qse_ntime_t* t
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
69
qse/include/qse/net/httpd.h
Normal file
69
qse/include/qse/net/httpd.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* $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 <htrd://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _QSE_NET_HTTPD_H_
|
||||
#define _QSE_NET_HTTPD_H_
|
||||
|
||||
#include <qse/types.h>
|
||||
#include <qse/macros.h>
|
||||
|
||||
typedef struct qse_httpd_t qse_httpd_t;
|
||||
struct qse_httpd_t
|
||||
{
|
||||
QSE_DEFINE_COMMON_FIELDS (httpd)
|
||||
|
||||
int stopreq;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
QSE_DEFINE_COMMON_FUNCTIONS (httpd)
|
||||
|
||||
/**
|
||||
* The qse_httpd_open() function creates a httpd processor.
|
||||
*/
|
||||
qse_httpd_t* qse_httpd_open (
|
||||
qse_mmgr_t* mmgr, /**< memory manager */
|
||||
qse_size_t xtnsize /**< extension size in bytes */
|
||||
);
|
||||
|
||||
/**
|
||||
* The qse_httpd_close() function destroys a httpd processor.
|
||||
*/
|
||||
void qse_httpd_close (
|
||||
qse_httpd_t* httpd
|
||||
);
|
||||
|
||||
qse_httpd_t* qse_httpd_init (
|
||||
qse_httpd_t* httpd,
|
||||
qse_mmgr_t* mmgr
|
||||
);
|
||||
|
||||
void qse_httpd_fini (
|
||||
qse_httpd_t* httpd
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -9,7 +9,8 @@ lib_LTLIBRARIES = libqsenet.la
|
||||
libqsenet_la_SOURCES = \
|
||||
http.c \
|
||||
htre.c \
|
||||
htrd.c
|
||||
htrd.c \
|
||||
httpd.c
|
||||
|
||||
libqsenet_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir)
|
||||
libqsenet_la_LIBADD = -lqsecmn
|
||||
|
@ -71,7 +71,7 @@ am__base_list = \
|
||||
am__installdirs = "$(DESTDIR)$(libdir)"
|
||||
LTLIBRARIES = $(lib_LTLIBRARIES)
|
||||
libqsenet_la_DEPENDENCIES =
|
||||
am_libqsenet_la_OBJECTS = http.lo htre.lo htrd.lo
|
||||
am_libqsenet_la_OBJECTS = http.lo htre.lo htrd.lo httpd.lo
|
||||
libqsenet_la_OBJECTS = $(am_libqsenet_la_OBJECTS)
|
||||
libqsenet_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
@ -241,7 +241,8 @@ lib_LTLIBRARIES = libqsenet.la
|
||||
libqsenet_la_SOURCES = \
|
||||
http.c \
|
||||
htre.c \
|
||||
htrd.c
|
||||
htrd.c \
|
||||
httpd.c
|
||||
|
||||
libqsenet_la_LDFLAGS = -version-info 1:0:0 -no-undefined -L../cmn -L$(libdir)
|
||||
libqsenet_la_LIBADD = -lqsecmn
|
||||
@ -322,6 +323,7 @@ distclean-compile:
|
||||
@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@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpd.Plo@am__quote@
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
|
@ -172,6 +172,7 @@ qse_htrd_t* qse_htrd_init (qse_htrd_t* http, qse_mmgr_t* mmgr)
|
||||
QSE_MEMSET (http, 0, QSE_SIZEOF(*http));
|
||||
http->mmgr = mmgr;
|
||||
|
||||
qse_mbs_init (&http->tmp.qparam, http->mmgr, 0);
|
||||
qse_mbs_init (&http->fed.b.raw, http->mmgr, 0);
|
||||
qse_mbs_init (&http->fed.b.tra, http->mmgr, 0);
|
||||
|
||||
@ -179,6 +180,7 @@ qse_htrd_t* qse_htrd_init (qse_htrd_t* http, qse_mmgr_t* mmgr)
|
||||
{
|
||||
qse_mbs_fini (&http->fed.b.tra);
|
||||
qse_mbs_fini (&http->fed.b.raw);
|
||||
qse_mbs_fini (&http->tmp.qparam);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
@ -192,6 +194,7 @@ void qse_htrd_fini (qse_htrd_t* http)
|
||||
clear_combined_headers (http);
|
||||
qse_mbs_fini (&http->fed.b.tra);
|
||||
qse_mbs_fini (&http->fed.b.raw);
|
||||
qse_mbs_fini (&http->tmp.qparam);
|
||||
}
|
||||
|
||||
static qse_htoc_t* parse_initial_line (
|
||||
@ -273,7 +276,7 @@ static qse_htoc_t* parse_initial_line (
|
||||
while (*p != '\0' && *p != '\n') p++;
|
||||
tmp.len = p - tmp.ptr;
|
||||
|
||||
if (qse_htre_setsmessage (&http->re, &tmp) <= -1) goto outofmem;
|
||||
if (qse_htre_setsmessagefromcstr (&http->re, &tmp) <= -1) goto outofmem;
|
||||
|
||||
/* adjust Connection: close for HTTP 1.0 or eariler */
|
||||
if (http->re.version.major < 1 ||
|
||||
@ -300,8 +303,12 @@ static qse_htoc_t* parse_initial_line (
|
||||
out = p;
|
||||
while (*p != '\0' && !is_space_octet(*p))
|
||||
{
|
||||
if (*p == '%')
|
||||
if (*p == '%' && param.ptr == QSE_NULL)
|
||||
{
|
||||
/* decode percence-encoded charaters in the
|
||||
* path part. if we're in the parameter string
|
||||
* part, we don't decode them. */
|
||||
|
||||
int q = xdigit_to_num(*(p+1));
|
||||
int w = xdigit_to_num(*(p+2));
|
||||
|
||||
@ -344,11 +351,11 @@ static qse_htoc_t* parse_initial_line (
|
||||
if (param.ptr)
|
||||
{
|
||||
param.len = out - param.ptr;
|
||||
if (qse_htre_setqparamstr (&http->re, ¶m) <= -1) goto outofmem;
|
||||
if (qse_htre_setqparamfromcstr (&http->re, ¶m) <= -1) goto outofmem;
|
||||
}
|
||||
else tmp.len = out - tmp.ptr;
|
||||
|
||||
if (qse_htre_setqpath (&http->re, &tmp) <= -1) goto outofmem;
|
||||
if (qse_htre_setqpathfromcstr (&http->re, &tmp) <= -1) goto outofmem;
|
||||
|
||||
/* skip spaces after the url part */
|
||||
do { p++; } while (is_space_octet(*p));
|
||||
@ -1100,7 +1107,7 @@ int qse_htrd_feed (qse_htrd_t* http, const qse_htoc_t* req, qse_size_t len)
|
||||
if (n <= -1)
|
||||
{
|
||||
if (http->errnum == QSE_HTRD_ENOERR)
|
||||
http->errnum = QSE_HTRD_EREQCBS;
|
||||
http->errnum = QSE_HTRD_ERECBS;
|
||||
|
||||
/* need to clear request on error?
|
||||
clear_feed (http); */
|
||||
@ -1237,7 +1244,7 @@ int qse_htrd_feed (qse_htrd_t* http, const qse_htoc_t* req, qse_size_t len)
|
||||
{
|
||||
QSE_ASSERTX (
|
||||
http->recbs.response != QSE_NULL,
|
||||
"set response callbacks before feeding"
|
||||
"set response callback before feeding"
|
||||
);
|
||||
|
||||
n = http->recbs.response (http, &http->re);
|
||||
@ -1246,7 +1253,7 @@ int qse_htrd_feed (qse_htrd_t* http, const qse_htoc_t* req, qse_size_t len)
|
||||
{
|
||||
QSE_ASSERTX (
|
||||
http->recbs.request != QSE_NULL,
|
||||
"set request callbacks before feeding"
|
||||
"set request callback before feeding"
|
||||
);
|
||||
|
||||
n = http->recbs.request (http, &http->re);
|
||||
@ -1255,7 +1262,7 @@ int qse_htrd_feed (qse_htrd_t* http, const qse_htoc_t* req, qse_size_t len)
|
||||
if (n <= -1)
|
||||
{
|
||||
if (http->errnum == QSE_HTRD_ENOERR)
|
||||
http->errnum = QSE_HTRD_EREQCBS;
|
||||
http->errnum = QSE_HTRD_ERECBS;
|
||||
|
||||
/* need to clear request on error?
|
||||
clear_feed (http); */
|
||||
@ -1310,7 +1317,7 @@ int qse_htrd_read (qse_htrd_t* http)
|
||||
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;
|
||||
if (http->errnum == QSE_HTRD_ENOERR) http->errnum = QSE_HTRD_ERECBS;
|
||||
return -1;
|
||||
}
|
||||
if (n == 0)
|
||||
@ -1322,3 +1329,108 @@ int qse_htrd_read (qse_htrd_t* http)
|
||||
return qse_htrd_feed (http, http->rbuf, n);
|
||||
}
|
||||
|
||||
int qse_htrd_scanqparam (qse_htrd_t* http, const qse_mcstr_t* cstr)
|
||||
{
|
||||
qse_mcstr_t key, val;
|
||||
const qse_htoc_t* p, * end;
|
||||
qse_htoc_t* out;
|
||||
|
||||
if (cstr == QSE_NULL) cstr = qse_htre_getqparamcstr(&http->re);
|
||||
|
||||
p = cstr->ptr;
|
||||
if (p == QSE_NULL) return 0; /* no param string to scan */
|
||||
|
||||
end = p + cstr->len;
|
||||
|
||||
/* a key and a value pair including two terminating null
|
||||
* can't exceed the the qparamstrlen + 2. only +1 below as there is
|
||||
* one more space for an internal terminating null */
|
||||
qse_mbs_setlen (&http->tmp.qparam, cstr->len + 1);
|
||||
|
||||
/* let out point to the beginning of the qparam buffer.
|
||||
* the loop below emits percent-decode key and value to this buffer. */
|
||||
out = QSE_MBS_PTR(&http->tmp.qparam);
|
||||
|
||||
key.ptr = out; key.len = 0;
|
||||
val.ptr = QSE_NULL; val.len = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if (p >= end || *p == '&' || *p == ';')
|
||||
{
|
||||
QSE_ASSERT (key.ptr != QSE_NULL);
|
||||
|
||||
*out++ = '\0';
|
||||
if (val.ptr == QSE_NULL)
|
||||
{
|
||||
if (key.len == 0)
|
||||
{
|
||||
/* both key and value are empty.
|
||||
* we don't need to do anything */
|
||||
goto next_octet;
|
||||
}
|
||||
|
||||
val.ptr = out;
|
||||
*out++ = '\0';
|
||||
QSE_ASSERT (val.len == 0);
|
||||
}
|
||||
|
||||
QSE_ASSERTX (
|
||||
http->recbs.qparamstr != QSE_NULL,
|
||||
"set request parameter string callback before scanning"
|
||||
);
|
||||
|
||||
http->errnum = QSE_HTRD_ENOERR;
|
||||
if (http->recbs.qparamstr (http, &key, &val) <= -1)
|
||||
{
|
||||
if (http->errnum == QSE_HTRD_ENOERR)
|
||||
http->errnum = QSE_HTRD_ERECBS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
next_octet:
|
||||
if (p >= end) break;
|
||||
p++;
|
||||
|
||||
out = QSE_MBS_PTR(&http->tmp.qparam);
|
||||
key.ptr = out; key.len = 0;
|
||||
val.ptr = QSE_NULL; val.len = 0;
|
||||
}
|
||||
else if (*p == '=')
|
||||
{
|
||||
*out++ = '\0'; p++;
|
||||
|
||||
val.ptr = out;
|
||||
/*val.len = 0; */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*p == '%' && p + 2 <= end)
|
||||
{
|
||||
int q = xdigit_to_num(*(p+1));
|
||||
if (q >= 0)
|
||||
{
|
||||
int w = xdigit_to_num(*(p+2));
|
||||
if (w >= 0)
|
||||
{
|
||||
/* unlike the path part, we don't care if it
|
||||
* contains a null character */
|
||||
*out++ = ((q << 4) + w);
|
||||
p += 3;
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*out++ = *p++;
|
||||
|
||||
next:
|
||||
if (val.ptr) val.len++;
|
||||
else key.len++;
|
||||
}
|
||||
}
|
||||
while (1);
|
||||
|
||||
qse_mbs_clear (&http->tmp.qparam);
|
||||
return 0;
|
||||
}
|
||||
|
@ -17,14 +17,14 @@ qse_htre_t* qse_htre_init (qse_htre_t* re, qse_mmgr_t* mmgr)
|
||||
|
||||
qse_mbs_init (&re->content, mmgr, 0);
|
||||
qse_mbs_init (&re->qpath_or_smesg, mmgr, 0);
|
||||
qse_mbs_init (&re->qparamstr, mmgr, 0);
|
||||
qse_mbs_init (&re->qparam, mmgr, 0);
|
||||
|
||||
return re;
|
||||
}
|
||||
|
||||
void qse_htre_fini (qse_htre_t* re)
|
||||
{
|
||||
qse_mbs_fini (&re->qparamstr);
|
||||
qse_mbs_fini (&re->qparam);
|
||||
qse_mbs_fini (&re->qpath_or_smesg);
|
||||
qse_mbs_fini (&re->content);
|
||||
qse_htb_fini (&re->hdrtab);
|
||||
@ -39,27 +39,20 @@ void qse_htre_clear (qse_htre_t* re)
|
||||
|
||||
qse_mbs_clear (&re->content);
|
||||
qse_mbs_clear (&re->qpath_or_smesg);
|
||||
qse_mbs_clear (&re->qparamstr);
|
||||
qse_mbs_clear (&re->qparam);
|
||||
|
||||
re->discard = 0;
|
||||
}
|
||||
|
||||
int qse_htre_setbuf (
|
||||
qse_htre_t* re, qse_htob_t* buf, const qse_mcstr_t* str)
|
||||
int qse_htre_setstrfromcstr (
|
||||
qse_htre_t* re, qse_htob_t* str, const qse_mcstr_t* cstr)
|
||||
{
|
||||
return (qse_mbs_ncpy (buf, str->ptr, str->len) == (qse_size_t)-1)? -1: 0;
|
||||
return (qse_mbs_ncpy (str, cstr->ptr, cstr->len) == (qse_size_t)-1)? -1: 0;
|
||||
}
|
||||
|
||||
void qse_htre_getbuf (
|
||||
qse_htre_t* re, const qse_htob_t* buf, qse_mcstr_t* str)
|
||||
int qse_htre_setstrfromxstr (
|
||||
qse_htre_t* re, qse_htob_t* str, const qse_mxstr_t* xstr)
|
||||
{
|
||||
str->ptr = QSE_MBS_PTR(buf);
|
||||
str->len = QSE_MBS_LEN(buf);
|
||||
return (qse_mbs_ncpy (str, xstr->ptr, xstr->len) == (qse_size_t)-1)? -1: 0;
|
||||
}
|
||||
|
||||
int qse_htre_setqparamstr (qse_htre_t* re, const qse_mcstr_t* str)
|
||||
{
|
||||
return (qse_mbs_ncpy (&re->qparamstr, str->ptr, str->len) == (qse_size_t)-1)? -1: 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -134,47 +134,15 @@ int qse_gethttpmethodtypefromstr (
|
||||
return -1;
|
||||
}
|
||||
|
||||
int qse_scanhttpparamstr (
|
||||
const qse_htoc_t* paramstr,
|
||||
qse_scanhttpparamstr_callback_t callback,
|
||||
void* ctx)
|
||||
int qse_gethttpdatetime (const qse_htoc_t* str, qse_ntime_t* t)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (key.len == 0) break;
|
||||
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++;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* TODO: */
|
||||
return -1;
|
||||
}
|
||||
|
||||
int qse_gethttpdatetimefromstr (const qse_mcstr_t* str, qse_ntime_t* t)
|
||||
{
|
||||
/* TODO: */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
182
qse/lib/net/httpd.c
Normal file
182
qse/lib/net/httpd.c
Normal file
@ -0,0 +1,182 @@
|
||||
#include <qse/net/httpd.h>
|
||||
#include <qse/net/htrd.h>
|
||||
|
||||
#include "../cmn/mem.h"
|
||||
#include <pthread.h>
|
||||
|
||||
QSE_IMPLEMENT_COMMON_FUNCTIONS (httpd)
|
||||
|
||||
|
||||
typedef struct client_t client_t;
|
||||
|
||||
struct client_t
|
||||
{
|
||||
int fd;
|
||||
#if 0
|
||||
struct sockaddr_storage addr;
|
||||
qse_htrd_t* htrd;
|
||||
|
||||
pthread_mutex_t action_mutex;
|
||||
struct
|
||||
{
|
||||
int offset;
|
||||
int count;
|
||||
client_action_t target[32];
|
||||
} action;
|
||||
#endif
|
||||
};
|
||||
|
||||
qse_httpd_t* qse_httpd_open (qse_mmgr_t* mmgr, qse_size_t xtnsize)
|
||||
{
|
||||
qse_httpd_t* httpd;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
httpd = (qse_httpd_t*) QSE_MMGR_ALLOC (
|
||||
mmgr, QSE_SIZEOF(*httpd) + xtnsize
|
||||
);
|
||||
if (httpd == QSE_NULL) return QSE_NULL;
|
||||
|
||||
if (qse_httpd_init (httpd, mmgr) == QSE_NULL)
|
||||
{
|
||||
QSE_MMGR_FREE (httpd->mmgr, httpd);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
return httpd;
|
||||
}
|
||||
|
||||
void qse_httpd_close (qse_httpd_t* httpd)
|
||||
{
|
||||
qse_httpd_fini (httpd);
|
||||
QSE_MMGR_FREE (httpd->mmgr, httpd);
|
||||
}
|
||||
|
||||
qse_httpd_t* qse_httpd_init (qse_httpd_t* httpd, qse_mmgr_t* mmgr)
|
||||
{
|
||||
QSE_MEMSET (httpd, 0, QSE_SIZEOF(*httpd));
|
||||
httpd->mmgr = mmgr;
|
||||
return httpd;
|
||||
}
|
||||
|
||||
void qse_httpd_fini (qse_httpd_t* httpd)
|
||||
{
|
||||
}
|
||||
|
||||
int qse_httpd_exec (qse_httpd_t* httpd)
|
||||
{
|
||||
#if 0
|
||||
int n, max, fd;
|
||||
fd_set r;
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
max = make_fd_set_from_client_array (&appdata.ca, s, &r, NULL);
|
||||
n = select (max + 1, &r, NULL, NULL, &tv);
|
||||
if (n <= -1)
|
||||
{
|
||||
if (errno == EINTR) continue;
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Error: select returned failure\n"));
|
||||
/* break; */
|
||||
continue;
|
||||
}
|
||||
if (n == 0) continue;
|
||||
|
||||
if (FD_ISSET(s, &r))
|
||||
{
|
||||
int flag, c;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
client_t* client;
|
||||
|
||||
c = accept (s, (struct sockaddr*)&addr, &addrlen);
|
||||
if (c <= -1)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Error: accept returned failure\n"));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* select() uses a fixed-size array so the file descriptor can not
|
||||
* exceeded FD_SETSIZE */
|
||||
if (c >= FD_SETSIZE)
|
||||
{
|
||||
close (c);
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Error: socket descriptor too high. probably too many clients\n"));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* set the nonblock flag in case read() after select() blocks
|
||||
* for various reasons - data received may be dropped after
|
||||
* arrival for wrong checksum, for example. */
|
||||
flag = fcntl (c, F_GETFL);
|
||||
if (flag >= 0) fcntl (c, F_SETFL, flag | O_NONBLOCK);
|
||||
|
||||
pthread_mutex_lock (&appdata.camutex);
|
||||
client = insert_into_client_array (&appdata.ca, c, &addr);
|
||||
pthread_mutex_unlock (&appdata.camutex);
|
||||
if (client == QSE_NULL)
|
||||
{
|
||||
close (c);
|
||||
qse_fprintf (QSE_STDERR, QSE_T("Error: failed to add a client\n"));
|
||||
continue;
|
||||
}
|
||||
qse_printf (QSE_T("connection %d accepted\n"), c);
|
||||
}
|
||||
|
||||
for (fd = 0; fd < appdata.ca.capa; fd++)
|
||||
{
|
||||
client_t* client = &appdata.ca.data[fd];
|
||||
|
||||
if (!client->http) continue;
|
||||
|
||||
if (FD_ISSET(client->fd, &r))
|
||||
{
|
||||
/* got input */
|
||||
if (qse_htrd_read (client->http) <= -1)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qse_httpd_loop (qse_httpd_t* httpd)
|
||||
{
|
||||
httpd->stopreq = 0;
|
||||
|
||||
while (!httpd->stopreq)
|
||||
{
|
||||
if (qse_httpd_exec (httpd) <= -1) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qse_httpd_stop (qse_httpd_t* httpd)
|
||||
{
|
||||
httpd->stopreq = 1;
|
||||
}
|
@ -303,9 +303,9 @@ 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 capture_param (void* ctx, const qse_mcstr_t* key, const qse_mcstr_t* val)
|
||||
static int capture_param (qse_htrd_t* http, const qse_mcstr_t* key, const qse_mcstr_t* val)
|
||||
{
|
||||
qse_printf (QSE_T("PARAM [%.*S] => [%.*S] \n"), (int)key->len, key->ptr, (int)val->len, val->ptr);
|
||||
qse_printf (QSE_T("PARAM %d[%S] => %d[%S] \n"), (int)key->len, key->ptr, (int)val->len, val->ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -322,9 +322,9 @@ qse_printf (QSE_T("REQUEST ==> [%S] version[%d.%d] method[%d]\n"),
|
||||
qse_htre_getminorversion(req),
|
||||
qse_htre_getqmethod(req)
|
||||
);
|
||||
if (qse_htre_getqparamstrlen(req) > 0)
|
||||
if (qse_htre_getqparamlen(req) > 0)
|
||||
{
|
||||
qse_printf (QSE_T("PARAMS ==> [%S]\n"), qse_htre_getqparamstrptr(req));
|
||||
qse_printf (QSE_T("PARAMS ==> [%S]\n"), qse_htre_getqparamptr(req));
|
||||
}
|
||||
|
||||
qse_htb_walk (&http->re.hdrtab, walk, QSE_NULL);
|
||||
@ -340,14 +340,10 @@ qse_printf (QSE_T("content = [%.*S]\n"),
|
||||
if (method == QSE_HTTP_GET || method == QSE_HTTP_POST)
|
||||
{
|
||||
int fd;
|
||||
qse_mchar_t* paramstr;
|
||||
|
||||
qse_printf (QSE_T("BEGIN SCANNING PARAM STR\n"));
|
||||
|
||||
paramstr = qse_htre_getqparamstrptr(req); /* if it is null, ? wasn't even provided */
|
||||
if (paramstr != QSE_NULL && qse_scanhttpparamstr (paramstr, capture_param, client) <= -1)
|
||||
//if (qse_htrd_scanqparam (http, qse_htre_getqparamcstr(req)) <= -1)
|
||||
if (qse_htrd_scanqparam (http, QSE_NULL) <= -1)
|
||||
{
|
||||
qse_printf (QSE_T("END SCANNING PARAM STR WITH ERROR\n"));
|
||||
const char* msg = "<html><head><title>INTERNAL SERVER ERROR</title></head><body><b>INTERNAL SERVER ERROR</b></body></html>";
|
||||
if (format_and_do (enqueue_format, client,
|
||||
"HTTP/%d.%d 500 Internal Server Error\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n",
|
||||
@ -360,7 +356,14 @@ qse_printf (QSE_T("failed to push action....\n"));
|
||||
}
|
||||
}
|
||||
|
||||
qse_printf (QSE_T("END SCANNING PARAM STR WITH SUCCESS\n"));
|
||||
if (method == QSE_HTTP_POST)
|
||||
{
|
||||
qse_printf (QSE_T("BEGIN FORM FIELDS=============\n"));
|
||||
if (qse_htrd_scanqparam (http, qse_htre_getcontentcstr(req)) <= -1)
|
||||
{
|
||||
}
|
||||
qse_printf (QSE_T("END FORM FIELDS=============\n"));
|
||||
}
|
||||
|
||||
fd = open (qse_htre_getqpathptr(req), O_RDONLY);
|
||||
if (fd <= -1)
|
||||
@ -416,10 +419,12 @@ qse_printf (QSE_T("empty file....\n"));
|
||||
|
||||
char text[128];
|
||||
snprintf (text, sizeof(text),
|
||||
"HTTP/%d.%d 200 OK\r\nContent-Length: %llu\r\n\r\n",
|
||||
"HTTP/%d.%d 200 OK\r\nContent-Length: %llu\r\nContent-Location: %s\r\n\r\n",
|
||||
qse_htre_getmajorversion(req),
|
||||
qse_htre_getminorversion(req),
|
||||
(unsigned long long)st.st_size);
|
||||
(unsigned long long)st.st_size,
|
||||
qse_htre_getqpathptr(req)
|
||||
);
|
||||
|
||||
#if 0
|
||||
if (enqueue_sendfmt_locked (client,
|
||||
@ -550,7 +555,8 @@ qse_htrd_recbs_t http_recbs =
|
||||
receive_octets,
|
||||
handle_request,
|
||||
handle_response,
|
||||
handle_expect_continue
|
||||
handle_expect_continue,
|
||||
capture_param
|
||||
};
|
||||
|
||||
int mkserver (const char* portstr)
|
||||
|
Loading…
Reference in New Issue
Block a user