still writing cgi support code

This commit is contained in:
hyung-hwan 2011-08-02 09:43:48 +00:00
parent 1b2392571c
commit 3634d16aaf
6 changed files with 200 additions and 21 deletions

View File

@ -37,11 +37,16 @@ enum qse_htrd_errnum_t
typedef enum qse_htrd_errnum_t qse_htrd_errnum_t; typedef enum qse_htrd_errnum_t qse_htrd_errnum_t;
/**
* The qse_htrd_option_t type defines various options to
* change the behavior of the qse_htrd_t reader.
*/
enum qse_htrd_option_t enum qse_htrd_option_t
{ {
QSE_HTRD_LEADINGEMPTYLINES = (1 << 0), QSE_HTRD_SKIPEMPTYLINES = (1 << 0), /**< skip leading empty lines before the initial line */
QSE_HTRD_REQUEST = (1 << 1), QSE_HTRD_SKIPINITIALLINE = (1 << 1), /**< skip processing an initial line */
QSE_HTRD_RESPONSE = (1 << 2) QSE_HTRD_REQUEST = (1 << 2), /**< parse input as a request */
QSE_HTRD_RESPONSE = (1 << 3) /**< parse input as a response */
}; };
typedef enum qse_htrd_option_t qse_htrd_option_t; typedef enum qse_htrd_option_t qse_htrd_option_t;

View File

@ -114,6 +114,13 @@ struct qse_htre_t
#define qse_htre_setdiscard(re,v) QSE_BLOCK((re)->discard = (v);) #define qse_htre_setdiscard(re,v) QSE_BLOCK((re)->discard = (v);)
typedef int (*qse_htre_header_walker_t) (
qse_htre_t* re,
const qse_mchar_t* key,
const qse_mchar_t* val,
void* ctx
);
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -143,8 +150,15 @@ int qse_htre_setstrfromxstr (
const qse_mxstr_t* xstr const qse_mxstr_t* xstr
); );
const qse_mchar_t* qse_htre_gethdrval ( const qse_mchar_t* qse_htre_getheaderval (
qse_htre_t* re, const qse_mchar_t* key qse_htre_t* re,
const qse_mchar_t* key
);
int qse_htre_walkheaders (
qse_htre_t* re,
qse_htre_header_walker_t walker,
void* ctx
); );
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -836,7 +836,7 @@ static QSE_INLINE int parse_initial_line_and_headers (
p = QSE_MBS_PTR(&htrd->fed.b.raw); p = QSE_MBS_PTR(&htrd->fed.b.raw);
if (htrd->option & QSE_HTRD_LEADINGEMPTYLINES) if (htrd->option & QSE_HTRD_SKIPEMPTYLINES)
while (is_whspace_octet(*p)) p++; while (is_whspace_octet(*p)) p++;
else else
while (is_space_octet(*p)) p++; while (is_space_octet(*p)) p++;
@ -844,8 +844,11 @@ static QSE_INLINE int parse_initial_line_and_headers (
QSE_ASSERT (*p != '\0'); QSE_ASSERT (*p != '\0');
/* parse the initial line */ /* parse the initial line */
p = parse_initial_line (htrd, p); if (!(htrd->option & QSE_HTRD_SKIPINITIALLINE))
if (p == QSE_NULL) return -1; {
p = parse_initial_line (htrd, p);
if (p == QSE_NULL) return -1;
}
/* parse header fields */ /* parse header fields */
do do
@ -1050,7 +1053,7 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len)
{ {
register qse_mchar_t b = *ptr++; register qse_mchar_t b = *ptr++;
if (htrd->option & QSE_HTRD_LEADINGEMPTYLINES && if (htrd->option & QSE_HTRD_SKIPEMPTYLINES &&
htrd->fed.s.plen <= 0 && is_whspace_octet(b)) htrd->fed.s.plen <= 0 && is_whspace_octet(b))
{ {
/* let's drop leading whitespaces across multiple /* let's drop leading whitespaces across multiple

View File

@ -72,7 +72,7 @@ int qse_htre_setstrfromxstr (
return (qse_mbs_ncpy (str, xstr->ptr, xstr->len) == (qse_size_t)-1)? -1: 0; return (qse_mbs_ncpy (str, xstr->ptr, xstr->len) == (qse_size_t)-1)? -1: 0;
} }
const qse_mchar_t* qse_htre_gethdrval ( const qse_mchar_t* qse_htre_getheaderval (
qse_htre_t* re, const qse_mchar_t* name) qse_htre_t* re, const qse_mchar_t* name)
{ {
qse_htb_pair_t* pair; qse_htb_pair_t* pair;
@ -81,3 +81,34 @@ const qse_mchar_t* qse_htre_gethdrval (
return QSE_HTB_VPTR(pair); return QSE_HTB_VPTR(pair);
} }
struct header_walker_ctx_t
{
qse_htre_t* re;
qse_htre_header_walker_t walker;
void* ctx;
int ret;
};
static qse_htb_walk_t walk_headers (qse_htb_t* htb, qse_htb_pair_t* pair, void* ctx)
{
struct header_walker_ctx_t* hwctx = (struct header_walker_ctx_t*)ctx;
if (hwctx->walker (hwctx->re, QSE_HTB_KPTR(pair), QSE_HTB_VPTR(pair), hwctx->ctx) <= -1)
{
hwctx->ret = -1;
return QSE_HTB_WALK_STOP;
}
return QSE_HTB_WALK_FORWARD;
}
int qse_htre_walkheaders (
qse_htre_t* re, qse_htre_header_walker_t walker, void* ctx)
{
struct header_walker_ctx_t hwctx;
hwctx.re = re;
hwctx.walker = walker;
hwctx.ctx = ctx;
hwctx.ret = 0;
qse_htb_walk (&re->hdrtab, walk_headers, &hwctx);
return hwctx.ret;
}

View File

@ -665,11 +665,78 @@ typedef struct task_cgi_t task_cgi_t;
struct task_cgi_t struct task_cgi_t
{ {
const qse_char_t* path; const qse_char_t* path;
qse_htrd_t* htrd;
qse_mbs_t* res;
qse_pio_t* pio; qse_pio_t* pio;
qse_mchar_t buf[MAX_SEND_SIZE]; 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;
struct cgi_htrd_xtn_t
{
task_cgi_t* cgi;
};
int walk_cgi_headers (qse_htre_t* req, const qse_mchar_t* key, const qse_mchar_t* val, void* ctx)
{
task_cgi_t* cgi = (task_cgi_t*)ctx;
if (qse_mbscmp (key, "Status") != 0)
{
if (qse_mbs_cat (cgi->res, key) == (qse_size_t)-1) return -1;
if (qse_mbs_cat (cgi->res, QSE_MT(": ")) == (qse_size_t)-1) return -1;
if (qse_mbs_cat (cgi->res, val) == (qse_size_t)-1) return -1;
if (qse_mbs_cat (cgi->res, QSE_MT("\r\n\r\n")) == (qse_size_t)-1) return -1;
}
return 0;
}
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;
status = qse_htre_getheaderval (req, QSE_MT("Status"));
if (status)
{
qse_mchar_t buf[128];
snprintf (buf, QSE_COUNTOF(buf),
QSE_MT("HTTP/%d.%d "),
qse_htre_getmajorversion(req),
qse_htre_getminorversion(req)
);
if (qse_mbs_cat (cgi->res, buf) == (qse_size_t)-1) return -1;
/* TODO: check the syntax of status value??? */
if (qse_mbs_cat (cgi->res, status) == (qse_size_t)-1) return -1;
if (qse_mbs_cat (cgi->res, QSE_MT("\r\n")) == (qse_size_t)-1) return -1;
}
else
{
qse_mchar_t buf[128];
snprintf (buf, QSE_COUNTOF(buf),
QSE_MT("HTTP/%d.%d 200 OK\r\n"),
qse_htre_getmajorversion(req),
qse_htre_getminorversion(req)
);
if (qse_mbs_cat (cgi->res, buf) == (qse_size_t)-1) return -1;
}
if (qse_htre_walkheaders (req, walk_cgi_headers, cgi) <= -1) return -1;
return 0;
}
static qse_htrd_recbs_t cgi_htrd_cbs =
{
cgi_htrd_handle_request,
QSE_NULL, /* not needed for CGI */
QSE_NULL /* not needed for CGI */
};
static int task_init_cgi ( static int task_init_cgi (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{ {
@ -686,7 +753,10 @@ static void task_fini_cgi (
{ {
task_cgi_t* cgi = (task_cgi_t*)task->ctx; task_cgi_t* cgi = (task_cgi_t*)task->ctx;
if (cgi->pio) qse_pio_close (cgi->pio); if (cgi->pio) qse_pio_close (cgi->pio);
if (cgi->res) qse_mbs_close (cgi->res);
if (cgi->htrd) qse_htrd_close (cgi->htrd);
} }
static int task_main_cgi_3 ( static int task_main_cgi_3 (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{ {
@ -742,6 +812,14 @@ static int task_main_cgi_2 (
cgi->buflen += n; cgi->buflen += n;
if (qse_htrd_feed (cgi->htrd, cgi->buf, cgi->buflen) <= -1)
{
/* TODO: logging */
return -1;
}
#if 0
n = send (client->handle.i, cgi->buf, cgi->buflen, 0); n = send (client->handle.i, cgi->buf, cgi->buflen, 0);
if (n <= -1) if (n <= -1)
{ {
@ -752,6 +830,7 @@ static int task_main_cgi_2 (
QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n); QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n);
cgi->buflen -= n; cgi->buflen -= n;
#endif
return 1; return 1;
} }
@ -760,15 +839,41 @@ static int task_main_cgi (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{ {
task_cgi_t* cgi = (task_cgi_t*)task->ctx; task_cgi_t* cgi = (task_cgi_t*)task->ctx;
cgi_htrd_xtn_t* xtn;
qse_printf (QSE_T("[pip open for %s]\n"), cgi->path); cgi->htrd = qse_htrd_open (httpd->mmgr, QSE_SIZEOF(cgi_htrd_xtn_t));
if (cgi->htrd == QSE_NULL)
{
qse_printf (QSE_T("internal server error....\n"));
return 0;
}
xtn = (cgi_htrd_xtn_t*) qse_htrd_getxtn (cgi->htrd);
xtn->cgi = cgi;
qse_htrd_setrecbs (cgi->htrd, &cgi_htrd_cbs);
qse_htrd_setoption (cgi->htrd, QSE_HTRD_SKIPINITIALLINE | QSE_HTRD_REQUEST);
cgi->res = qse_mbs_open (httpd->mmgr, 0, 256);
if (cgi->res == QSE_NULL)
{
/* TODO: entask internal server errror */
qse_htrd_close (cgi->htrd);
qse_printf (QSE_T("internal server error....\n"));
return 0;
}
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);
if (cgi->pio == QSE_NULL) if (cgi->pio == QSE_NULL)
{ {
/* TODO: entask internal server errror */ /* TODO: entask internal server errror */
qse_mbs_close (cgi->res);
qse_htrd_close (cgi->htrd);
qse_printf (QSE_T("internal server error....\n")); qse_printf (QSE_T("internal server error....\n"));
return 0; return 0;
} }
else
{
}
task->main = task_main_cgi_2; /* cause this function to be called subsequently */ task->main = task_main_cgi_2; /* cause this function to be called subsequently */
@ -794,3 +899,20 @@ qse_httpd_task_t* qse_httpd_entaskcgi (
QSE_SIZEOF(task_cgi_t) + ((qse_strlen(path) + 1) * QSE_SIZEOF(*path)) QSE_SIZEOF(task_cgi_t) + ((qse_strlen(path) + 1) * QSE_SIZEOF(*path))
); );
} }
/*------------------------------------------------------------------------*/
/*
typedef struct task_proxy_t task_proxy_t;
struct task_proxy_t
{
}
qse_httpd_task_t* qse_httpd_entaskproxy (...)
{
}
*/
/*------------------------------------------------------------------------*/

View File

@ -2,12 +2,8 @@
#include <qse/net/httpd.h> #include <qse/net/httpd.h>
#include <qse/cmn/stdio.h> #include <qse/cmn/stdio.h>
#include <qse/cmn/main.h> #include <qse/cmn/main.h>
#include <qse/cmn/str.h>
#include <signal.h> #include <signal.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#define MAX_SENDFILE_SIZE 4096 #define MAX_SENDFILE_SIZE 4096
typedef struct httpd_xtn_t httpd_xtn_t; typedef struct httpd_xtn_t httpd_xtn_t;
@ -60,24 +56,31 @@ qse_printf (QSE_T("content = [%.*S]\n"),
const qse_mchar_t* rangestr; const qse_mchar_t* rangestr;
qse_http_range_t range; qse_http_range_t range;
const qse_mchar_t* qpath = qse_htre_getqpathptr(req);
const qse_mchar_t* dot = qse_mbsrchr (qpath, QSE_MT('.'));
if (dot && qse_mbscmp (dot, QSE_MT(".cgi")) == 0)
{
qse_httpd_entaskcgi (httpd, client, QSE_NULL, QSE_T("/bin/ls -l /etc"));
goto done;
}
rangestr = qse_htre_gethdrval (req, "Range"); rangestr = qse_htre_gethdrval (req, "Range");
if (rangestr && qse_parsehttprange (rangestr, &range) <= -1) if (rangestr && qse_parsehttprange (rangestr, &range) <= -1)
{ {
#if 0 #if 0
qse_httpd_entaskstatictext (httpd, client, QSE_MT("HTTP/1.1 416 Requested range not satisfiable\r\nContent-Length: 5\r\n\r\nA\r\n\r\n")); 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 #endif
qse_httpd_entaskcgi (httpd, client, QSE_NULL, QSE_T("/bin/ls -l /etc"));
#if 0
const qse_mchar_t* msg; const qse_mchar_t* msg;
msg = QSE_MT("<html><head><title>Requested range not satisfiable</title></head><body><b>REQUESTED RANGE NOT SATISFIABLE</b></body></html>"); msg = QSE_MT("<html><head><title>Requested range not satisfiable</title></head><body><b>REQUESTED RANGE NOT SATISFIABLE</b></body></html>");
x = qse_httpd_entaskformat (httpd, client, 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"), 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, req->version.major, req->version.minor,
(int)qse_mbslen(msg) + 4, msg (int)qse_mbslen(msg) + 4, msg
); );
if (x == QSE_NULL) goto oops; if (x == QSE_NULL) goto oops;
#endif
} }
else else
{ {
@ -102,6 +105,7 @@ qse_httpd_entaskcgi (httpd, client, QSE_NULL, QSE_T("/bin/ls -l /etc"));
if (x == QSE_NULL) goto oops; if (x == QSE_NULL) goto oops;
} }
done:
if (req->attr.connection_close) if (req->attr.connection_close)
{ {
x = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL); x = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);