started adding cgi support.

enhanced qse_httpd_entask() and related functions to support entasking within a task handler.
This commit is contained in:
hyung-hwan 2011-07-30 02:14:04 +00:00
parent 1d41b3fb2a
commit 1b2392571c
7 changed files with 330 additions and 157 deletions

View File

@ -87,7 +87,7 @@ struct qse_httpd_task_t
qse_httpd_task_init_t init; qse_httpd_task_init_t init;
qse_httpd_task_fini_t fini; qse_httpd_task_fini_t fini;
qse_httpd_task_main_t main; qse_httpd_task_main_t main;
void* ctx; void* ctx;
}; };
#ifdef __cplusplus #ifdef __cplusplus
@ -155,51 +155,65 @@ void qse_httpd_markclientbad (
#define qse_httpd_gettaskxtn(httpd,task) ((void*)(task+1)) #define qse_httpd_gettaskxtn(httpd,task) ((void*)(task+1))
int qse_httpd_entask ( qse_httpd_task_t* qse_httpd_entask (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred,
const qse_httpd_task_t* task, const qse_httpd_task_t* task,
qse_size_t xtnsize qse_size_t xtnsize
); );
int qse_httpd_entasktext ( qse_httpd_task_t* qse_httpd_entaskdisconnect (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_mchar_t* text const qse_httpd_task_t* pred
); );
int qse_httpd_entaskstatictext ( qse_httpd_task_t* qse_httpd_entasktext (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_mchar_t* text const qse_httpd_task_t* pred,
const qse_mchar_t* text
); );
int qse_httpd_entaskformat ( qse_httpd_task_t* qse_httpd_entaskstatictext (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_mchar_t* fmt, const qse_httpd_task_t* pred,
const qse_mchar_t* text
);
qse_httpd_task_t* qse_httpd_entaskformat (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
const qse_httpd_task_t* pred,
const qse_mchar_t* fmt,
... ...
); );
int qse_httpd_entaskfile ( qse_httpd_task_t* qse_httpd_entaskfile (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
qse_ubi_t handle, const qse_httpd_task_t* pred,
qse_foff_t offset, qse_ubi_t handle,
qse_foff_t size qse_foff_t offset,
qse_foff_t size
); );
int qse_httpd_entaskpath ( qse_httpd_task_t* qse_httpd_entaskpath (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client, qse_httpd_client_t* client,
const qse_httpd_task_t* pred,
const qse_mchar_t* name, const qse_mchar_t* name,
const qse_http_range_t* range, const qse_http_range_t* range,
const qse_http_version_t* version const qse_http_version_t* version
); );
int qse_httpd_entaskdisconnect ( qse_httpd_task_t* qse_httpd_entaskcgi (
qse_httpd_t* httpd, qse_httpd_t* httpd,
qse_httpd_client_t* client qse_httpd_client_t* client,
const qse_httpd_task_t* pred,
const qse_char_t* path
); );
void* qse_httpd_allocmem ( void* qse_httpd_allocmem (

View File

@ -33,7 +33,7 @@ static QSE_INLINE int is_whspace_octet (qse_mchar_t c)
static QSE_INLINE int is_space_octet (qse_mchar_t c) static QSE_INLINE int is_space_octet (qse_mchar_t c)
{ {
return c == ' ' || c == '\t' || c == '\r'; return c == QSE_MT(' ') || c == QSE_MT('\t') || c == QSE_MT('\r');
} }
static QSE_INLINE int is_purespace_octet (qse_mchar_t c) static QSE_INLINE int is_purespace_octet (qse_mchar_t c)
@ -71,18 +71,19 @@ static QSE_INLINE int is_xdigit_octet (qse_mchar_t c)
static QSE_INLINE int digit_to_num (qse_mchar_t c) static QSE_INLINE int digit_to_num (qse_mchar_t c)
{ {
if (c >= '0' && c <= '9') return c - '0'; if (c >= QSE_MT('0') && c <= QSE_MT('9')) return c - QSE_MT('0');
return -1; return -1;
} }
static QSE_INLINE int xdigit_to_num (qse_mchar_t c) static QSE_INLINE int xdigit_to_num (qse_mchar_t c)
{ {
if (c >= '0' && c <= '9') return c - '0'; if (c >= QSE_MT('0') && c <= QSE_MT('9')) return c - QSE_MT('0');
if (c >= 'A' && c <= 'Z') return c - 'A' + 10; if (c >= QSE_MT('A') && c <= QSE_MT('Z')) return c - QSE_MT('A') + 10;
if (c >= 'a' && c <= 'z') return c - 'a' + 10; if (c >= QSE_MT('a') && c <= QSE_MT('z')) return c - QSE_MT('a') + 10;
return -1; return -1;
} }
static QSE_INLINE int push_to_buffer ( static QSE_INLINE int push_to_buffer (
qse_htrd_t* htrd, qse_htob_t* octb, qse_htrd_t* htrd, qse_htob_t* octb,
const qse_mchar_t* ptr, qse_size_t len) const qse_mchar_t* ptr, qse_size_t len)

View File

@ -132,7 +132,8 @@ QSE_INLINE void* qse_httpd_allocmem (qse_httpd_t* httpd, qse_size_t size)
return ptr; return ptr;
} }
QSE_INLINE void* qse_httpd_reallocmem (qse_httpd_t* httpd, void* ptr, qse_size_t size) QSE_INLINE void* qse_httpd_reallocmem (
qse_httpd_t* httpd, void* ptr, qse_size_t size)
{ {
void* nptr = QSE_MMGR_REALLOC (httpd->mmgr, ptr, size); void* nptr = QSE_MMGR_REALLOC (httpd->mmgr, ptr, size);
if (nptr == QSE_NULL) httpd->errnum = QSE_HTTPD_ENOMEM; if (nptr == QSE_NULL) httpd->errnum = QSE_HTTPD_ENOMEM;
@ -144,9 +145,10 @@ QSE_INLINE void qse_httpd_freemem (qse_httpd_t* httpd, void* ptr)
QSE_MMGR_FREE (httpd->mmgr, ptr); QSE_MMGR_FREE (httpd->mmgr, ptr);
} }
static int enqueue_task_unlocked ( static qse_httpd_task_t* enqueue_task_unlocked (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd, qse_httpd_client_t* client,
const qse_httpd_task_t* task, qse_size_t xtnsize) const qse_httpd_task_t* pred, const qse_httpd_task_t* task,
qse_size_t xtnsize)
{ {
task_queue_node_t* node; task_queue_node_t* node;
@ -157,8 +159,9 @@ static int enqueue_task_unlocked (
return -1; return -1;
} }
*/ */
node = qse_httpd_allocmem (httpd, QSE_SIZEOF(*node) + xtnsize); node = (task_queue_node_t*)
if (node == QSE_NULL) return -1; qse_httpd_allocmem (httpd, QSE_SIZEOF(*node) + xtnsize);
if (node == QSE_NULL) return QSE_NULL;
node->task = *task; node->task = *task;
@ -170,43 +173,59 @@ static int enqueue_task_unlocked (
if (httpd->errnum == QSE_HTTPD_ENOERR) if (httpd->errnum == QSE_HTTPD_ENOERR)
httpd->errnum = QSE_HTTPD_ETASK; httpd->errnum = QSE_HTTPD_ETASK;
qse_httpd_freemem (httpd, node); qse_httpd_freemem (httpd, node);
return -1; return QSE_NULL;
} }
} }
node->next = QSE_NULL; if (pred)
node->prev = client->task.queue.tail;
if (client->task.queue.tail)
{ {
client->task.queue.tail->next = node; task_queue_node_t* prev;
/* TODO: confirm if this calculation works all the time,
* especially regarding structure alignment */
prev = (task_queue_node_t*)
((qse_byte_t*)pred - (QSE_SIZEOF(*prev) - QSE_SIZEOF(*pred)));
node->next = prev->next;
node->prev = prev;
if (prev->next) prev->next->prev = node;
else client->task.queue.tail = node;
prev->next = node;
} }
else else
{ {
client->task.queue.head = node; node->next = QSE_NULL;
node->prev = client->task.queue.tail;
if (client->task.queue.tail)
client->task.queue.tail->next = node;
else
client->task.queue.head = node;
client->task.queue.tail = node;
} }
client->task.queue.tail = node;
client->task.queue.count++; client->task.queue.count++;
return 0; return &node->task;
} }
static int enqueue_task_locked ( static qse_httpd_task_t* enqueue_task_locked (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd, qse_httpd_client_t* client,
const qse_httpd_task_t* task, qse_size_t xtnsize) const qse_httpd_task_t* pred, const qse_httpd_task_t* task,
qse_size_t xtnsize)
{ {
#if defined(HAVE_PTHREAD) #if defined(HAVE_PTHREAD)
if (httpd->threaded) if (httpd->threaded)
{ {
int ret; qse_httpd_task_t* ret;
pthread_mutex_lock (&client->task.mutex); pthread_mutex_lock (&client->task.mutex);
ret = enqueue_task_unlocked (httpd, client, task, xtnsize); ret = enqueue_task_unlocked (httpd, client, pred, task, xtnsize);
pthread_mutex_unlock (&client->task.mutex); pthread_mutex_unlock (&client->task.mutex);
return ret; return ret;
} }
else else
{ {
#endif #endif
return enqueue_task_unlocked (httpd, client, task, xtnsize); return enqueue_task_unlocked (httpd, client, pred, task, xtnsize);
#if defined(HAVE_PTHREAD) #if defined(HAVE_PTHREAD)
} }
#endif #endif
@ -641,7 +660,8 @@ static void perform_task (qse_httpd_t* httpd, qse_httpd_client_t* client)
if (n <= -1) if (n <= -1)
{ {
dequeue_task_locked (httpd, client); dequeue_task_locked (httpd, client);
shutdown (client->handle.i, SHUT_RDWR); /*shutdown (client->handle.i, SHUT_RDWR);*/
client->bad = 1;
} }
else if (n == 0) else if (n == 0)
{ {
@ -1154,13 +1174,14 @@ void qse_httpd_clearlisteners (qse_httpd_t* httpd)
} }
#endif #endif
int qse_httpd_entask ( qse_httpd_task_t* qse_httpd_entask (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd, qse_httpd_client_t* client,
const qse_httpd_task_t* task, qse_size_t xtnsize) const qse_httpd_task_t* pred, const qse_httpd_task_t* task,
qse_size_t xtnsize)
{ {
int ret; qse_httpd_task_t* ret;
ret = enqueue_task_locked (httpd, client, task, xtnsize); ret = enqueue_task_locked (httpd, client, pred, task, xtnsize);
if (ret <= -1) client->bad = 1; /* mark this client bad */ if (ret == QSE_NULL) client->bad = 1; /* mark this client bad */
#if defined(HAVE_PTHREAD) #if defined(HAVE_PTHREAD)
else if (httpd->threaded) pthread_cond_signal (&httpd->client.cond); else if (httpd->threaded) pthread_cond_signal (&httpd->client.cond);
#endif #endif
@ -1174,3 +1195,4 @@ void qse_httpd_markclientbad (qse_httpd_t* httpd, qse_httpd_client_t* client)
* like memory allocation failure */ * like memory allocation failure */
client->bad = 1; client->bad = 1;
} }

View File

@ -55,7 +55,7 @@ struct task_queue_node_t
{ {
task_queue_node_t* next; task_queue_node_t* next;
task_queue_node_t* prev; task_queue_node_t* prev;
qse_httpd_task_t task; qse_httpd_task_t task;
}; };
struct qse_httpd_client_t struct qse_httpd_client_t

View File

@ -28,7 +28,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#define MAX_SENDFILE_SIZE 4096 #define MAX_SEND_SIZE 4096
#ifdef HAVE_SYS_SENDFILE_H #ifdef HAVE_SYS_SENDFILE_H
# include <sys/sendfile.h> # include <sys/sendfile.h>
@ -36,7 +36,7 @@
qse_ssize_t sendfile ( qse_ssize_t sendfile (
int out_fd, int in_fd, qse_foff_t* offset, qse_size_t count) int out_fd, int in_fd, qse_foff_t* offset, qse_size_t count)
{ {
qse_mchar_t buf[MAX_SENDFILE_SIZE]; qse_mchar_t buf[MAX_SEND_SIZE];
qse_ssize_t n; qse_ssize_t n;
if (offset && lseek (in_fd, *offset, SEEK_SET) != *offset) if (offset && lseek (in_fd, *offset, SEEK_SET) != *offset)
@ -46,7 +46,7 @@ qse_ssize_t sendfile (
n = read (in_fd, buf, count); n = read (in_fd, buf, count);
if (n == (qse_ssize_t)-1 || n == 0) return n; if (n == (qse_ssize_t)-1 || n == 0) return n;
n = write (out_fd, buf, n); n = send (out_fd, buf, n, 0);
if (n > 0 && offset) *offset = *offset + n; if (n > 0 && offset) *offset = *offset + n;
return n; return n;
@ -64,14 +64,17 @@ static int task_main_disconnect (
return 0; return 0;
} }
int qse_httpd_entaskdisconnect (qse_httpd_t* httpd, qse_httpd_client_t* client) qse_httpd_task_t* qse_httpd_entaskdisconnect (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
const qse_httpd_task_t* pred)
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
QSE_MEMSET (&task, 0, QSE_SIZEOF(task)); QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
task.main = task_main_disconnect; task.main = task_main_disconnect;
return qse_httpd_entask (httpd, client, &task, 0); return qse_httpd_entask (httpd, client, pred, &task, 0);
} }
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
@ -83,7 +86,7 @@ static int task_main_statictext (
qse_size_t count = 0; qse_size_t count = 0;
const qse_mchar_t* ptr = (const qse_mchar_t*)task->ctx; const qse_mchar_t* ptr = (const qse_mchar_t*)task->ctx;
while (*ptr != QSE_MT('\0') && count < MAX_SENDFILE_SIZE) while (*ptr != QSE_MT('\0') && count < MAX_SEND_SIZE)
{ {
ptr++; count++; ptr++; count++;
} }
@ -105,8 +108,11 @@ static int task_main_statictext (
return 1; /* more work to do */ return 1; /* more work to do */
} }
int qse_httpd_entaskstatictext ( qse_httpd_task_t* qse_httpd_entaskstatictext (
qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_mchar_t* text) qse_httpd_t* httpd,
qse_httpd_client_t* client,
const qse_httpd_task_t* pred,
const qse_mchar_t* text)
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
@ -114,7 +120,7 @@ int qse_httpd_entaskstatictext (
task.main = task_main_statictext; task.main = task_main_statictext;
task.ctx = (void*)text; task.ctx = (void*)text;
return qse_httpd_entask (httpd, client, &task, 0); return qse_httpd_entask (httpd, client, pred, &task, 0);
} }
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
@ -146,7 +152,7 @@ static int task_main_text (
qse_size_t count; qse_size_t count;
task_text_t* ctx = (task_text_t*)task->ctx; task_text_t* ctx = (task_text_t*)task->ctx;
count = MAX_SENDFILE_SIZE; count = MAX_SEND_SIZE;
if (count >= ctx->left) count = ctx->left; if (count >= ctx->left) count = ctx->left;
/* TODO: do i need to add code to skip this send if count is 0? */ /* TODO: do i need to add code to skip this send if count is 0? */
@ -166,8 +172,11 @@ static int task_main_text (
return 1; /* more work to do */ return 1; /* more work to do */
} }
int qse_httpd_entasktext ( qse_httpd_task_t* qse_httpd_entasktext (
qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_mchar_t* text) qse_httpd_t* httpd,
qse_httpd_client_t* client,
const qse_httpd_task_t* pred,
const qse_mchar_t* text)
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
task_text_t data; task_text_t data;
@ -182,7 +191,7 @@ int qse_httpd_entasktext (
task.ctx = &data; task.ctx = &data;
return qse_httpd_entask ( return qse_httpd_entask (
httpd, client, &task, QSE_SIZEOF(data) + data.left); httpd, client, pred, &task, QSE_SIZEOF(data) + data.left);
} }
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
@ -223,7 +232,7 @@ static int task_main_format (
qse_size_t count; qse_size_t count;
task_format_t* ctx = (task_format_t*)task->ctx; task_format_t* ctx = (task_format_t*)task->ctx;
count = MAX_SENDFILE_SIZE; count = MAX_SEND_SIZE;
if (count >= ctx->left) count = ctx->left; if (count >= ctx->left) count = ctx->left;
n = send ( n = send (
@ -242,8 +251,11 @@ static int task_main_format (
return 1; /* more work to do */ return 1; /* more work to do */
} }
int qse_httpd_entaskformat ( qse_httpd_task_t* qse_httpd_entaskformat (
qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_mchar_t* fmt, ...) qse_httpd_t* httpd,
qse_httpd_client_t* client,
const qse_httpd_task_t* pred,
const qse_mchar_t* fmt, ...)
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
task_format_t data; task_format_t data;
@ -266,7 +278,7 @@ int qse_httpd_entaskformat (
qse_size_t capa = 256; qse_size_t capa = 256;
buf = (qse_mchar_t*) qse_httpd_allocmem (httpd, (capa + 1) * QSE_SIZEOF(*buf)); buf = (qse_mchar_t*) qse_httpd_allocmem (httpd, (capa + 1) * QSE_SIZEOF(*buf));
if (buf == QSE_NULL) return -1; if (buf == QSE_NULL) return QSE_NULL;
/* an old vsnprintf behaves differently from C99 standard. /* an old vsnprintf behaves differently from C99 standard.
* thus, it returns -1 when it can't write all the input given. */ * thus, it returns -1 when it can't write all the input given. */
@ -286,7 +298,7 @@ int qse_httpd_entaskformat (
capa = capa * 2; capa = capa * 2;
buf = (qse_mchar_t*) qse_httpd_allocmem (httpd, (capa + 1) * QSE_SIZEOF(*buf)); buf = (qse_mchar_t*) qse_httpd_allocmem (httpd, (capa + 1) * QSE_SIZEOF(*buf));
if (buf == QSE_NULL) return -1; if (buf == QSE_NULL) return QSE_NULL;
} }
else break; else break;
} }
@ -297,7 +309,7 @@ int qse_httpd_entaskformat (
* have been written not including the terminating '\0' * have been written not including the terminating '\0'
* if the _data buffer were large enough */ * if the _data buffer were large enough */
buf = (qse_mchar_t*) qse_httpd_allocmem (httpd, (bytes_req + 1) * QSE_SIZEOF(*buf)); buf = (qse_mchar_t*) qse_httpd_allocmem (httpd, (bytes_req + 1) * QSE_SIZEOF(*buf));
if (buf == QSE_NULL) return -1; if (buf == QSE_NULL) return QSE_NULL;
va_start (ap, fmt); va_start (ap, fmt);
#if defined(_WIN32) && defined(_MSC_VER) #if defined(_WIN32) && defined(_MSC_VER)
@ -313,7 +325,7 @@ int qse_httpd_entaskformat (
qse_httpd_freemem (httpd, buf); qse_httpd_freemem (httpd, buf);
httpd->errnum = QSE_HTTPD_EINTERN; httpd->errnum = QSE_HTTPD_EINTERN;
return -1; return QSE_NULL;
} }
} }
@ -329,7 +341,7 @@ int qse_httpd_entaskformat (
task.ctx = &data; task.ctx = &data;
return qse_httpd_entask ( return qse_httpd_entask (
httpd, client, &task, QSE_SIZEOF(data)); httpd, client, pred, &task, QSE_SIZEOF(data));
} }
/* TODO: send wide character string when QSE_CHAR_IS_WCHAR */ /* TODO: send wide character string when QSE_CHAR_IS_WCHAR */
@ -367,7 +379,7 @@ static int task_main_file (
qse_size_t count; qse_size_t count;
task_file_t* ctx = (task_file_t*)task->ctx; task_file_t* ctx = (task_file_t*)task->ctx;
count = MAX_SENDFILE_SIZE; count = MAX_SEND_SIZE;
if (count >= ctx->left) count = ctx->left; if (count >= ctx->left) count = ctx->left;
/* TODO: more adjustment needed for OS with different sendfile semantics... */ /* TODO: more adjustment needed for OS with different sendfile semantics... */
@ -396,9 +408,13 @@ static int task_main_file (
return 1; /* more work to do */ return 1; /* more work to do */
} }
int qse_httpd_entaskfile ( qse_httpd_task_t* qse_httpd_entaskfile (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd,
qse_ubi_t handle, qse_foff_t offset, qse_foff_t size) qse_httpd_client_t* client,
const qse_httpd_task_t* pred,
qse_ubi_t handle,
qse_foff_t offset,
qse_foff_t size)
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
task_file_t data; task_file_t data;
@ -414,7 +430,7 @@ int qse_httpd_entaskfile (
task.fini = task_fini_file; task.fini = task_fini_file;
task.ctx = &data; task.ctx = &data;
return qse_httpd_entask (httpd, client, &task, QSE_SIZEOF(data)); return qse_httpd_entask (httpd, client, pred, &task, QSE_SIZEOF(data));
} }
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
@ -448,18 +464,20 @@ static int task_main_path (
task_path_t* data = (task_path_t*)task->ctx; task_path_t* data = (task_path_t*)task->ctx;
qse_ubi_t handle; qse_ubi_t handle;
struct stat st; struct stat st;
int x; qse_httpd_task_t* x = task;
qse_printf (QSE_T("opending file %S\n"), data->name);
handle.i = open (data->name, O_RDONLY); handle.i = open (data->name, O_RDONLY);
if (handle.i <= -1) if (handle.i <= -1)
{ {
const qse_mchar_t* msg = QSE_MT("<html><head><title>Not found</title></head><body><b>REQUESTED FILE NOT FOUND</b></body></html>"); const qse_mchar_t* msg = QSE_MT("<html><head><title>Not found</title></head><body><b>REQUESTED FILE NOT FOUND</b></body></html>");
x = qse_httpd_entaskformat (httpd, client, x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 404 Not found\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"), QSE_MT("HTTP/%d.%d 404 Not found\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
data->version.major, data->version.minor, data->version.major, data->version.minor,
(int)qse_mbslen(msg) + 4, msg (int)qse_mbslen(msg) + 4, msg
); );
goto done; goto no_file_send;
} }
fcntl (handle.i, F_SETFD, FD_CLOEXEC); fcntl (handle.i, F_SETFD, FD_CLOEXEC);
@ -467,12 +485,27 @@ static int task_main_path (
{ {
const qse_mchar_t* msg = QSE_MT("<html><head><title>Not found</title></head><body><b>REQUESTED FILE NOT FOUND</b></body></html>"); const qse_mchar_t* msg = QSE_MT("<html><head><title>Not found</title></head><body><b>REQUESTED FILE NOT FOUND</b></body></html>");
x = qse_httpd_entaskformat (httpd, client, x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 404 Not found\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"), QSE_MT("HTTP/%d.%d 404 Not found\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
data->version.major, data->version.minor, data->version.major, data->version.minor,
(int)qse_mbslen(msg) + 4, msg (int)qse_mbslen(msg) + 4, msg
); );
goto done; goto no_file_send;
}
if (S_ISDIR(st.st_mode))
{
/* TODO: directory listing */
const qse_mchar_t* msg = QSE_MT("<html><head><title>Directory Listing</title></head><body><li>file1<li>file2<li>file3</body></html>");
x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 200 OK\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n"),
data->version.major, data->version.minor,
(int)qse_mbslen(msg) + 4, msg
);
goto no_file_send;
} }
if (st.st_size < 0) st.st_size = 0; /* can this happen? */ if (st.st_size < 0) st.st_size = 0; /* can this happen? */
@ -494,12 +527,13 @@ static int task_main_path (
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, x,
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"),
data->version.major, data->version.minor, data->version.major, data->version.minor,
(int)qse_mbslen(msg) + 4, msg (int)qse_mbslen(msg) + 4, msg
); );
goto done; goto no_file_send;
} }
if (data->range.to >= st.st_size) data->range.to = st.st_size - 1; if (data->range.to >= st.st_size) data->range.to = st.st_size - 1;
@ -512,7 +546,8 @@ static int task_main_path (
} }
#if (QSE_SIZEOF_LONG_LONG > 0) #if (QSE_SIZEOF_LONG_LONG > 0)
x = qse_httpd_entaskformat (httpd, client, x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 206 Partial content\r\n%s%sContent-Length: %llu\r\nContent-Location: %s\r\nContent-Range: bytes %llu-%llu/%llu\r\n\r\n"), QSE_MT("HTTP/%d.%d 206 Partial content\r\n%s%sContent-Length: %llu\r\nContent-Location: %s\r\nContent-Range: bytes %llu-%llu/%llu\r\n\r\n"),
data->version.major, data->version.major,
data->version.minor, data->version.minor,
@ -525,7 +560,8 @@ static int task_main_path (
(unsigned long long)st.st_size (unsigned long long)st.st_size
); );
#else #else
x = qse_httpd_entaskformat (httpd, client, x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 206 Partial content\r\n%s%sContent-Length: %lu\r\nContent-Location: %s\r\nContent-Range: bytes %lu-%lu/%lu\r\n\r\n"), QSE_MT("HTTP/%d.%d 206 Partial content\r\n%s%sContent-Length: %lu\r\nContent-Location: %s\r\nContent-Range: bytes %lu-%lu/%lu\r\n\r\n"),
data->version.major, data->version.major,
data->version.minor, data->version.minor,
@ -538,14 +574,15 @@ static int task_main_path (
(unsigned long)st.st_size (unsigned long)st.st_size
); );
#endif #endif
if (x <= -1) goto done; if (x)
{
x = qse_httpd_entaskfile ( x = qse_httpd_entaskfile (
httpd, client, handle, httpd, client, x,
data->range.from, handle,
(data->range.to - data->range.from + 1) data->range.from,
); (data->range.to - data->range.from + 1)
if (x <= -1) goto done; );
}
} }
else else
{ {
@ -556,11 +593,12 @@ static int task_main_path (
{ {
httpd->errnum = QSE_HTTPD_ENOERR; httpd->errnum = QSE_HTTPD_ENOERR;
mime_type = httpd->cbs->file.getmimetype (httpd, data->name); mime_type = httpd->cbs->file.getmimetype (httpd, data->name);
/*TODO: how to handle an error... */ /*TODO: how to handle an error... */
} }
#if (QSE_SIZEOF_LONG_LONG > 0) #if (QSE_SIZEOF_LONG_LONG > 0)
x = qse_httpd_entaskformat (httpd, client, x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 200 OK\r\n%s%sContent-Length: %llu\r\nContent-Location: %s\r\n\r\n"), QSE_MT("HTTP/%d.%d 200 OK\r\n%s%sContent-Length: %llu\r\nContent-Location: %s\r\n\r\n"),
data->version.major, data->version.major,
data->version.minor, data->version.minor,
@ -570,7 +608,8 @@ static int task_main_path (
data->name data->name
); );
#else #else
x = qse_httpd_entaskformat (httpd, client, x = qse_httpd_entaskformat (
httpd, client, x,
QSE_MT("HTTP/%d.%d 200 OK\r\n%s%sContent-Length: %lu\r\nContent-Location: %s\r\n\r\n"), QSE_MT("HTTP/%d.%d 200 OK\r\n%s%sContent-Length: %lu\r\nContent-Location: %s\r\n\r\n"),
data->version.major, data->version.major,
data->version.minor, data->version.minor,
@ -580,22 +619,26 @@ static int task_main_path (
data->name data->name
); );
#endif #endif
if (x <= -1) goto done; if (x)
{
x = qse_httpd_entaskfile (httpd, client, handle, 0, st.st_size); x = qse_httpd_entaskfile (
if (x <= -1) goto done; httpd, client, x, handle, 0, st.st_size);
}
} }
return 0; return (x == QSE_NULL)? -1: 0;
done: no_file_send:
if (handle.i >= 0) close (handle.i); if (handle.i >= 0) close (handle.i);
return x; return (x == QSE_NULL)? -1: 0;
} }
int qse_httpd_entaskpath ( qse_httpd_task_t* qse_httpd_entaskpath (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_t* httpd,
const qse_mchar_t* name, const qse_http_range_t* range, 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) const qse_http_version_t* verison)
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
@ -612,62 +655,142 @@ int qse_httpd_entaskpath (
task.main = task_main_path; task.main = task_main_path;
task.ctx = &data; task.ctx = &data;
return qse_httpd_entask (httpd, client, &task, return qse_httpd_entask (httpd, client, pred, &task,
QSE_SIZEOF(task_path_t) + qse_mbslen(name) + 1); QSE_SIZEOF(task_path_t) + qse_mbslen(name) + 1);
} }
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if 0 typedef struct task_cgi_t task_cgi_t;
typedef struct httpd_task_cgi_t httpd_task_cgi_t; struct task_cgi_t
struct httpd_task_cgi_t
{ {
const qse_char_t* path;
qse_pio_t* pio; qse_pio_t* pio;
qse_mchar_t buf[MAX_SEND_SIZE];
qse_size_t buflen;
}; };
static int httpd_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)
{ {
httpd_task_cgi_t* xtn = qse_httpd_gettaskxtn (httpd, task); task_cgi_t* xtn = (task_cgi_t*)qse_httpd_gettaskxtn (httpd, task);
QSE_MEMSET (xtn, 0, QSE_SIZEOF(*xtn)); QSE_MEMSET (xtn, 0, QSE_SIZEOF(*xtn));
xtn->pio = qse_pio_open (httpd->mmgr, task->ctx); qse_strcpy ((qse_char_t*)(xtn + 1), task->ctx);
if (xtn->pio == QSE_NULL) xtn->path = (qse_char_t*)(xtn + 1);
{
httpd->errnum = QSE_HTTPD_ECGI;
return -1;
}
task->ctx = xtn; task->ctx = xtn;
return 0; return 0;
} }
static void httpd_fini_cgi ( static void task_fini_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)
{ {
httpd_task_cgi_t* xtn = task->ctx; task_cgi_t* cgi = (task_cgi_t*)task->ctx;
qse_pio_close (xtn->pio); if (cgi->pio) qse_pio_close (cgi->pio);
} }
static int task_main_cgi_3 (
static void httpd_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)
{ {
/* TODO */ task_cgi_t* cgi = (task_cgi_t*)task->ctx;
return -1; qse_ssize_t n;
QSE_ASSERT (cgi->pio != QSE_NULL);
n = send (client->handle.i, cgi->buf, cgi->buflen, 0);
if (n <= -1)
{
/* can't return internal server error any more... */
/* TODO: logging ... */
return -1;
}
QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n);
cgi->buflen -= n;
return (cgi->buflen > 0)? 1: 0;
} }
int qse_httpd_entaskcgi ( static int task_main_cgi_2 (
qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_char_t* path) qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{
task_cgi_t* cgi = (task_cgi_t*)task->ctx;
qse_ssize_t n;
QSE_ASSERT (cgi->pio != QSE_NULL);
/* <- can i make it non-block?? or use select??? pio_tryread()? */
n = qse_pio_read (
cgi->pio,
&cgi->buf[cgi->buflen],
QSE_SIZEOF(cgi->buf) - cgi->buflen,
QSE_PIO_OUT
);
if (n <= -1)
{
/* can't return internal server error any more... */
/* TODO: logging ... */
return -1;
}
if (n == 0)
{
if (cgi->buflen > 0)
{
task->main = task_main_cgi_3;
return task_main_cgi_3 (httpd, client, task);
}
else return 0;
}
cgi->buflen += n;
n = send (client->handle.i, cgi->buf, cgi->buflen, 0);
if (n <= -1)
{
/* can't return internal server error any more... */
/* TODO: logging ... */
return -1;
}
QSE_MEMCPY (&cgi->buf[0], &cgi->buf[n], cgi->buflen - n);
cgi->buflen -= n;
return 1;
}
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;
qse_printf (QSE_T("[pip 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_printf (QSE_T("internal server error....\n"));
return 0;
}
task->main = task_main_cgi_2; /* cause this function to be called subsequently */
return task_main_cgi_2 (httpd, client, task); /* let me call it here once */
}
qse_httpd_task_t* qse_httpd_entaskcgi (
qse_httpd_t* httpd,
qse_httpd_client_t* client,
const qse_httpd_task_t* pred,
const qse_char_t* path)
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
httpd_task_cgi_t data;
QSE_MEMSET (&task, 0, QSE_SIZEOF(task)); QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
task.init = httpd_init_cgi; task.init = task_init_cgi;
task.main = httpd_main_cgi; task.fini = task_fini_cgi;
task.fini = httpd_fini_cgi; task.main = task_main_cgi;
task.ctx = path; task.ctx = (void*)path;
return qse_httpd_entask (httpd, client, &task, QSE_SIZEOF(data)); return qse_httpd_entask (
httpd, client, pred, &task,
QSE_SIZEOF(task_cgi_t) + ((qse_strlen(path) + 1) * QSE_SIZEOF(*path))
);
} }
#endif

View File

@ -44,7 +44,7 @@ static int pio1 (const qse_char_t* cmd, int oflags, qse_pio_hid_t rhid)
qse_ssize_t i; qse_ssize_t i;
/*qse_pio_canread (pio, QSE_PIO_ERR, 1000)*/ /*qse_pio_canread (pio, QSE_PIO_ERR, 1000)*/
qse_ssize_t n = qse_pio_read (pio, buf, sizeof(buf), rhid); qse_ssize_t n = qse_pio_read (pio, buf, QSE_SIZEOF(buf), rhid);
if (n == 0) break; if (n == 0) break;
if (n <= -1) if (n <= -1)
{ {

View File

@ -26,6 +26,7 @@ static int handle_request (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req) qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req)
{ {
int method; int method;
qse_httpd_task_t* x;
#if 0 #if 0
httpd_xtn_t* xtn = (httpd_xtn_t*) qse_httpd_getxtn (httpd); httpd_xtn_t* xtn = (httpd_xtn_t*) qse_httpd_getxtn (httpd);
@ -58,11 +59,16 @@ 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;
int x;
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
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"));
#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,
@ -70,35 +76,42 @@ qse_printf (QSE_T("content = [%.*S]\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 <= -1) goto oops; if (x == QSE_NULL) goto oops;
#endif
}
else
{
x = qse_httpd_entaskpath (
httpd, client, QSE_NULL,
qse_htre_getqpathptr(req),
(rangestr? &range: QSE_NULL),
qse_htre_getversion(req)
);
if (x == QSE_NULL) goto oops;
} }
x = qse_httpd_entaskpath (
httpd, client,
qse_htre_getqpathptr(req),
(rangestr? &range: QSE_NULL),
qse_htre_getversion(req)
);
if (x <= -1) goto oops;
} }
else 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>"); const qse_mchar_t* msg = QSE_MT("<html><head><title>Method not allowed</title></head><body><b>REQUEST METHOD NOT ALLOWED</b></body></html>");
if (qse_httpd_entaskformat (httpd, client, 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"), 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, req->version.major, req->version.minor,
(int)qse_mbslen(msg) + 4, msg) <= -1) goto oops; (int)qse_mbslen(msg) + 4, msg
);
if (x == QSE_NULL) goto oops;
} }
if (req->attr.connection_close) if (req->attr.connection_close)
{ {
if (qse_httpd_entaskdisconnect (httpd, client) <= -1) return -1; x = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL);
if (x == QSE_NULL) goto oops;
} }
return 0; return 0;
oops: oops:
qse_httpd_markclientbad (httpd, client); /*qse_httpd_markclientbad (httpd, client);*/
return 0; return 0;
} }