added qse_httpd_entaskerror() and enhanced qse_httpd_entaskpath()

This commit is contained in:
hyung-hwan 2012-01-31 14:32:20 +00:00
parent fcd14fff1c
commit 7a7127b89f
3 changed files with 149 additions and 117 deletions

View File

@ -157,6 +157,8 @@ qse_httpd_task_t* qse_httpd_entask (
qse_size_t xtnsize
);
/* -------------------------------------------- */
qse_httpd_task_t* qse_httpd_entaskdisconnect (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
@ -185,6 +187,8 @@ qse_httpd_task_t* qse_httpd_entaskformat (
...
);
/* -------------------------------------------- */
qse_httpd_task_t* qse_httpd_entaskfile (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
@ -202,14 +206,22 @@ qse_httpd_task_t* qse_httpd_entaskdir (
int chunked
);
/* -------------------------------------------- */
qse_httpd_task_t* qse_httpd_entaskerror (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
const qse_httpd_task_t* task,
int code,
const qse_htre_t* req
);
qse_httpd_task_t* qse_httpd_entaskpath (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
const qse_httpd_task_t* pred,
const qse_mchar_t* name,
const qse_http_range_t* range,
const qse_http_version_t* version,
int keepalive
const qse_htre_t* req
);
qse_httpd_task_t* qse_httpd_entaskcgi (
@ -220,6 +232,8 @@ qse_httpd_task_t* qse_httpd_entaskcgi (
const qse_htre_t* req
);
/* -------------------------------------------- */
void* qse_httpd_allocmem (
qse_httpd_t* httpd,
qse_size_t size

View File

@ -113,50 +113,6 @@ static qse_ssize_t xsendfile (
}
#endif
static qse_httpd_task_t* entask_error (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task,
int code, qse_http_version_t* version, int keepalive)
{
const qse_mchar_t* smsg;
const qse_mchar_t* lmsg;
switch (code)
{
case 403:
smsg = QSE_MT("Forbidden");
lmsg = QSE_MT("<html><head><title>Directory Listing Forbidden</title></head><body><b>DIRECTORY LISTING FORBIDDEN<b></body></html>");
break;
case 404:
smsg = QSE_MT("Not Found");
lmsg = QSE_MT("<html><head><title>Not Found</title></head><body><b>REQUESTED PATH NOT FOUND<b></body></html>");
break;
case 416:
smsg = QSE_MT("Requested Range Not Satisfiable");
lmsg = QSE_MT("<html><head><title>Requested Range Not Satsfiable</title></head><body><b>REQUESTED RANGE NOT SATISFIABLE<b></body></html>");
break;
case 500:
smsg = QSE_MT("Internal Server Error");
lmsg = QSE_MT("<html><head><title>Internal Server Error</title></head><body><b>INTERNAL SERVER ERROR<b></body></html>");
default:
smsg = QSE_MT("Unknown");
lmsg = QSE_MT("<html><head><title>Unknown Error</title></head><body><b>UNKNOWN ERROR<b></body></html>");
break;
}
return qse_httpd_entaskformat (
httpd, client, task,
QSE_MT("HTTP/%d.%d %d %s\r\nConnection: %s\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
version->major, version->minor, code, smsg,
(keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
(int)qse_mbslen(lmsg) + 4, lmsg
);
}
/*------------------------------------------------------------------------*/
static int task_main_disconnect (
@ -451,6 +407,80 @@ qse_printf (QSE_T("SEND: [%.*S]\n"), (int)l, buf);
/*------------------------------------------------------------------------*/
static qse_httpd_task_t* entask_error (
qse_httpd_t* httpd, qse_httpd_client_t* client,
const qse_httpd_task_t* task, int code,
const qse_http_version_t* version, int keepalive)
{
const qse_mchar_t* smsg;
const qse_mchar_t* lmsg;
switch (code)
{
case 403:
smsg = QSE_MT("Forbidden");
lmsg = QSE_MT("<html><head><title>Forbidden</title></head><body><b>FORBIDDEN<b></body></html>");
break;
case 404:
smsg = QSE_MT("Not Found");
lmsg = QSE_MT("<html><head><title>Not Found</title></head><body><b>REQUESTED PATH NOT FOUND<b></body></html>");
break;
case 405:
smsg = QSE_MT("Method Not Allowed");
lmsg = QSE_MT("<html><head><title>Method Not Allowed</title></head><body><b>REQUESTED METHOD NOT ALLOWED<b></body></html>");
break;
case 416:
smsg = QSE_MT("Requested Range Not Satisfiable");
lmsg = QSE_MT("<html><head><title>Requested Range Not Satsfiable</title></head><body><b>REQUESTED RANGE NOT SATISFIABLE<b></body></html>");
break;
case 500:
smsg = QSE_MT("Internal Server Error");
lmsg = QSE_MT("<html><head><title>Internal Server Error</title></head><body><b>INTERNAL SERVER ERROR<b></body></html>");
break;
case 501:
smsg = QSE_MT("Not Implemented");
lmsg = QSE_MT("<html><head><title>Not Implemented</title></head><body><b>NOT IMPLEMENTED<b></body></html>");
break;
case 502:
smsg = QSE_MT("Bad Gateway");
lmsg = QSE_MT("<html><head><title>Bad Gateway</title></head><body><b>BAD GATEWAY<b></body></html>");
break;
case 503:
smsg = QSE_MT("Service Unavailable");
lmsg = QSE_MT("<html><head><title>Service Unavailable</title></head><body><b>SERVICE UNAVAILABLE<b></body></html>");
break;
default:
smsg = QSE_MT("Unknown");
lmsg = QSE_MT("<html><head><title>Unknown Error</title></head><body><b>UNKNOWN ERROR<b></body></html>");
break;
}
return qse_httpd_entaskformat (
httpd, client, task,
QSE_MT("HTTP/%d.%d %d %s\r\nConnection: %s\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
version->major, version->minor, code, smsg,
(keepalive? QSE_MT("keep-alive"): QSE_MT("close")),
(int)qse_mbslen(lmsg) + 4, lmsg
);
}
qse_httpd_task_t* qse_httpd_entaskerror (
qse_httpd_t* httpd, qse_httpd_client_t* client,
const qse_httpd_task_t* task, int code, const qse_htre_t* req)
{
return entask_error (httpd, client, task, code, qse_htre_getversion(req), req->attr.keepalive);
}
/*------------------------------------------------------------------------*/
typedef struct task_file_t task_file_t;
struct task_file_t
{
@ -618,14 +648,14 @@ static int task_main_dir (
ctx->buflen = SIZE_CHLEN + SIZE_CHLENCRLF;
/* free space remaing in the buffer for the chunk data */
ctx->bufrem = QSE_COUNTOF(ctx->buf) - ctx->buflen - CHENDCRLF;
ctx->bufrem = QSE_COUNTOF(ctx->buf) - ctx->buflen - SIZE_CHENDCRLF;
if (ctx->footer_pending)
{
x = snprintf (
&ctx->buf[ctx->buflen],
ctx->bufrem,
"</ul></body></html>\r\n0\r\n");
QSE_MT("</ul></body></html>\r\n0\r\n"));
if (x == -1 || x >= ctx->bufrem)
{
/* return an error if the buffer is too small to hold the
@ -637,8 +667,8 @@ static int task_main_dir (
ctx->chunklen = ctx->buflen - 5; /* -5 for \r\n0\r\n added above */
/* CHENDCRLF */
ctx->buf[ctx->buflen++] = '\r';
ctx->buf[ctx->buflen++] = '\n';
ctx->buf[ctx->buflen++] = QSE_MT('\r');
ctx->buf[ctx->buflen++] = QSE_MT('\n');
goto set_chunklen;
}
@ -651,7 +681,7 @@ static int task_main_dir (
x = snprintf (
&ctx->buf[ctx->buflen],
ctx->bufrem,
"<html><head><title>Directory Listing</title></head><body>index of xxxx<ul>"
QSE_MT("<html><head><title>Directory Listing</title></head><body>index of xxxx<ul>")
);
if (x == -1 || x >= ctx->bufrem)
{
@ -678,15 +708,15 @@ static int task_main_dir (
x = snprintf (
&ctx->buf[ctx->buflen],
ctx->bufrem,
"</ul></body></html>\r\n0\r\n");
QSE_MT("</ul></body></html>\r\n0\r\n"));
if (x == -1 || x >= ctx->bufrem)
{
ctx->footer_pending = 1;
ctx->chunklen = ctx->buflen;
/* CHENDCRLF */
ctx->buf[ctx->buflen++] = '\r';
ctx->buf[ctx->buflen++] = '\n';
ctx->buf[ctx->buflen++] = QSE_MT('\r');
ctx->buf[ctx->buflen++] = QSE_MT('\n');
}
else
{
@ -694,8 +724,8 @@ static int task_main_dir (
ctx->chunklen = ctx->buflen - 5;
/* CHENDCRLF */
ctx->buf[ctx->buflen++] = '\r';
ctx->buf[ctx->buflen++] = '\n';
ctx->buf[ctx->buflen++] = QSE_MT('\r');
ctx->buf[ctx->buflen++] = QSE_MT('\n');
}
break;
}
@ -704,11 +734,11 @@ static int task_main_dir (
x = snprintf (
&ctx->buf[ctx->buflen],
ctx->bufrem,
"<li><a href='%s%s'>%s%s</a></li>",
QSE_MT("<li><a href='%s%s'>%s%s</a></li>"),
ctx->dent->d_name,
(ctx->dent->d_type == DT_DIR? "/": ""),
(ctx->dent->d_type == DT_DIR? QSE_MT("/"): QSE_MT("")),
ctx->dent->d_name,
(ctx->dent->d_type == DT_DIR? "/": "")
(ctx->dent->d_type == DT_DIR? QSE_MT("/"): QSE_MT(""))
);
if (x == -1 || x >= ctx->bufrem)
{
@ -716,8 +746,8 @@ static int task_main_dir (
ctx->chunklen = ctx->buflen;
/* CHENDCRLF */
ctx->buf[ctx->buflen++] = '\r';
ctx->buf[ctx->buflen++] = '\n';
ctx->buf[ctx->buflen++] = QSE_MT('\r');
ctx->buf[ctx->buflen++] = QSE_MT('\n');
break;
}
else
@ -735,15 +765,15 @@ set_chunklen:
/* right alignment with space padding on the left */
x = snprintf (
ctx->buf, (SIZE_CHLEN + SIZE_CHLENCRLF) - 1,
"%*lX", (int)(SIZE_CHLEN + SIZE_CHLENCRLF - 2),
QSE_MT("%*lX"), (int)(SIZE_CHLEN + SIZE_CHLENCRLF - 2),
(unsigned long)(ctx->chunklen - (SIZE_CHLEN + SIZE_CHLENCRLF)));
/* CHLENCRLF */
ctx->buf[x] = '\r';
ctx->buf[x+1] = '\n';
ctx->buf[x] = QSE_MT('\r');
ctx->buf[x+1] = QSE_MT('\n');
/* skip leading space padding */
for (x = 0; ctx->buf[x] == ' '; x++) ctx->buflen--;
for (x = 0; ctx->buf[x] == QSE_MT(' '); x++) ctx->buflen--;
ctx->bufpos = x;
send_dirlist:
@ -1140,19 +1170,29 @@ qse_httpd_task_t* qse_httpd_entaskpath (
qse_httpd_client_t* client,
const qse_httpd_task_t* pred,
const qse_mchar_t* name,
const qse_http_range_t* range,
const qse_http_version_t* verison,
int keepalive)
const qse_htre_t* req)
{
qse_httpd_task_t task;
task_path_t data;
const qse_mchar_t* range;
QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
data.name = name;
if (range) data.range = *range;
else data.range.type = QSE_HTTP_RANGE_NONE;
data.version = *verison;
data.keepalive = keepalive;
data.version = *qse_htre_getversion(req);
data.keepalive = req->attr.keepalive;
range = qse_htre_getheaderval(req, QSE_MT("Range"));
if (range)
{
if (qse_parsehttprange (range, &data.range) <= -1)
{
return entask_error (httpd, client, pred, 416, &data.version, data.keepalive);
}
}
else
{
data.range.type = QSE_HTTP_RANGE_NONE;
}
QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
task.init = task_init_path;
@ -1179,6 +1219,7 @@ struct task_cgi_t
const qse_mchar_t* path;
qse_http_version_t version;
int keepalive; /* taken from the request */
qse_env_t* env;
qse_pio_t* pio;
@ -1376,6 +1417,7 @@ static int task_init_cgi (
qse_mbscpy ((qse_mchar_t*)(xtn + 1), arg->path);
xtn->path = (qse_mchar_t*)(xtn + 1);
xtn->version = *qse_htre_getversion(arg->req);
xtn->keepalive = arg->req->attr.keepalive;
xtn->env = makecgienv (httpd, client, arg->req);
if (xtn->env == QSE_NULL) xtn->init_failed = 1;
@ -1541,7 +1583,7 @@ static int task_main_cgi_3 (
qse_ssize_t n;
qse_size_t count;
qse_printf (QSE_T("task_main_cgi_3\n"));
qse_printf (QSE_T("cgi_3\n"));
count = MAX_SEND_SIZE;
if (count >= cgi->res_left) count = cgi->res_left;
@ -1665,11 +1707,18 @@ static int task_main_cgi (
return task_main_cgi_2 (httpd, client, task); /* let me call it here once */
oops:
if (cgi->res) qse_mbs_close (cgi->res);
if (cgi->htrd) qse_htrd_close (cgi->htrd);
if (cgi->res)
{
qse_mbs_close (cgi->res);
cgi->res = QSE_NULL;
}
if (cgi->htrd)
{
qse_htrd_close (cgi->htrd);
cgi->htrd = QSE_NULL;
}
/* TODO: keep alive.... cgi->disconnect???? */
return (entask_error (httpd, client, task, 500, &cgi->version, 0) == QSE_NULL)? -1: 0;
return (entask_error (httpd, client, task, 500, &cgi->version, cgi->keepalive) == QSE_NULL)? -1: 0;
}
qse_httpd_task_t* qse_httpd_entaskcgi (

View File

@ -60,9 +60,6 @@ qse_printf (QSE_T("content = [%.*S]\n"),
if (method == QSE_HTTP_GET || method == QSE_HTTP_POST)
{
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('.'));
@ -74,53 +71,25 @@ qse_printf (QSE_T("content = [%.*S]\n"),
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));
x = qse_httpd_entasknphcgi (
httpd, client, QSE_NULL, qpath, req);
if (x == QSE_NULL) goto oops;
#endif
}
else
{
rangestr = qse_htre_getheaderval (req, QSE_MT("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("<html><head><title>Requested range not satisfiable</title></head><body><b>REQUESTED RANGE NOT SATISFIABLE</b></body></html>");
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),
req->attr.keepalive
);
if (x == QSE_NULL) goto oops;
}
/* file or directory */
x = qse_httpd_entaskpath (
httpd, client, QSE_NULL, qpath, req);
if (x == QSE_NULL) goto oops;
}
}
else
{
const qse_mchar_t* msg = QSE_MT("<html><head><title>Method not allowed</title></head><body><b>REQUEST METHOD NOT ALLOWED</b></body></html>");
x = qse_httpd_entaskformat (
httpd, client, QSE_NULL,
QSE_MT("HTTP/%d.%d 405 Method not allowed\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
);
x = qse_httpd_entaskerror (httpd, client, QSE_NULL, 405, req);
if (x == QSE_NULL) goto oops;
}
done:
if (!req->attr.keepalive)
{
x = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);