still writing cgi support code
This commit is contained in:
parent
1b2392571c
commit
3634d16aaf
@ -37,11 +37,16 @@ enum 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
|
||||
{
|
||||
QSE_HTRD_LEADINGEMPTYLINES = (1 << 0),
|
||||
QSE_HTRD_REQUEST = (1 << 1),
|
||||
QSE_HTRD_RESPONSE = (1 << 2)
|
||||
QSE_HTRD_SKIPEMPTYLINES = (1 << 0), /**< skip leading empty lines before the initial line */
|
||||
QSE_HTRD_SKIPINITIALLINE = (1 << 1), /**< skip processing an initial line */
|
||||
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;
|
||||
|
@ -114,6 +114,13 @@ struct qse_htre_t
|
||||
|
||||
#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
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -143,8 +150,15 @@ int qse_htre_setstrfromxstr (
|
||||
const qse_mxstr_t* xstr
|
||||
);
|
||||
|
||||
const qse_mchar_t* qse_htre_gethdrval (
|
||||
qse_htre_t* re, const qse_mchar_t* key
|
||||
const qse_mchar_t* qse_htre_getheaderval (
|
||||
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
|
||||
|
@ -836,7 +836,7 @@ static QSE_INLINE int parse_initial_line_and_headers (
|
||||
|
||||
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++;
|
||||
else
|
||||
while (is_space_octet(*p)) p++;
|
||||
@ -844,8 +844,11 @@ static QSE_INLINE int parse_initial_line_and_headers (
|
||||
QSE_ASSERT (*p != '\0');
|
||||
|
||||
/* parse the initial line */
|
||||
p = parse_initial_line (htrd, p);
|
||||
if (p == QSE_NULL) return -1;
|
||||
if (!(htrd->option & QSE_HTRD_SKIPINITIALLINE))
|
||||
{
|
||||
p = parse_initial_line (htrd, p);
|
||||
if (p == QSE_NULL) return -1;
|
||||
}
|
||||
|
||||
/* parse header fields */
|
||||
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++;
|
||||
|
||||
if (htrd->option & QSE_HTRD_LEADINGEMPTYLINES &&
|
||||
if (htrd->option & QSE_HTRD_SKIPEMPTYLINES &&
|
||||
htrd->fed.s.plen <= 0 && is_whspace_octet(b))
|
||||
{
|
||||
/* let's drop leading whitespaces across multiple
|
||||
|
@ -72,7 +72,7 @@ int qse_htre_setstrfromxstr (
|
||||
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_htb_pair_t* pair;
|
||||
@ -81,3 +81,34 @@ const qse_mchar_t* qse_htre_gethdrval (
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -665,11 +665,78 @@ 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_pio_t* pio;
|
||||
|
||||
qse_mchar_t buf[MAX_SEND_SIZE];
|
||||
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 (
|
||||
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;
|
||||
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 (
|
||||
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;
|
||||
|
||||
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);
|
||||
if (n <= -1)
|
||||
{
|
||||
@ -752,6 +830,7 @@ static int task_main_cgi_2 (
|
||||
|
||||
QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n);
|
||||
cgi->buflen -= n;
|
||||
#endif
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
if (cgi->pio == QSE_NULL)
|
||||
{
|
||||
/* TODO: entask internal server errror */
|
||||
qse_mbs_close (cgi->res);
|
||||
qse_htrd_close (cgi->htrd);
|
||||
qse_printf (QSE_T("internal server error....\n"));
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
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))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
typedef struct task_proxy_t task_proxy_t;
|
||||
struct task_proxy_t
|
||||
{
|
||||
}
|
||||
|
||||
qse_httpd_task_t* qse_httpd_entaskproxy (...)
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -2,12 +2,8 @@
|
||||
#include <qse/net/httpd.h>
|
||||
#include <qse/cmn/stdio.h>
|
||||
#include <qse/cmn/main.h>
|
||||
#include <qse/cmn/str.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
|
||||
typedef struct httpd_xtn_t httpd_xtn_t;
|
||||
@ -60,24 +56,31 @@ qse_printf (QSE_T("content = [%.*S]\n"),
|
||||
const qse_mchar_t* rangestr;
|
||||
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");
|
||||
if (rangestr && qse_parsehttprange (rangestr, &range) <= -1)
|
||||
{
|
||||
#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
|
||||
qse_httpd_entaskcgi (httpd, client, QSE_NULL, QSE_T("/bin/ls -l /etc"));
|
||||
|
||||
#if 0
|
||||
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>");
|
||||
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"),
|
||||
req->version.major, req->version.minor,
|
||||
(int)qse_mbslen(msg) + 4, msg
|
||||
);
|
||||
if (x == QSE_NULL) goto oops;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -102,6 +105,7 @@ qse_httpd_entaskcgi (httpd, client, QSE_NULL, QSE_T("/bin/ls -l /etc"));
|
||||
if (x == QSE_NULL) goto oops;
|
||||
}
|
||||
|
||||
done:
|
||||
if (req->attr.connection_close)
|
||||
{
|
||||
x = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
|
||||
|
Loading…
x
Reference in New Issue
Block a user