written more http code

This commit is contained in:
2011-07-08 10:16:19 +00:00
parent afbbdd03ea
commit ec02be14e5
13 changed files with 493 additions and 124 deletions

View File

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

View File

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

View File

@ -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, &param) <= -1) goto outofmem;
if (qse_htre_setqparamfromcstr (&http->re, &param) <= -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;
}

View File

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

View File

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