diff --git a/qse/include/qse/net/httpd.h b/qse/include/qse/net/httpd.h index ff9f98e2..c86eb6ab 100644 --- a/qse/include/qse/net/httpd.h +++ b/qse/include/qse/net/httpd.h @@ -87,7 +87,7 @@ struct qse_httpd_task_t qse_httpd_task_init_t init; qse_httpd_task_fini_t fini; qse_httpd_task_main_t main; - void* ctx; + void* ctx; }; #ifdef __cplusplus @@ -155,51 +155,65 @@ void qse_httpd_markclientbad ( #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_client_t* client, + const qse_httpd_task_t* pred, const qse_httpd_task_t* task, qse_size_t xtnsize ); -int qse_httpd_entasktext ( - qse_httpd_t* httpd, - qse_httpd_client_t* client, - const qse_mchar_t* text +qse_httpd_task_t* qse_httpd_entaskdisconnect ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + const qse_httpd_task_t* pred ); -int qse_httpd_entaskstatictext ( - qse_httpd_t* httpd, - qse_httpd_client_t* client, - const qse_mchar_t* text +qse_httpd_task_t* qse_httpd_entasktext ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + const qse_httpd_task_t* pred, + const qse_mchar_t* text ); -int qse_httpd_entaskformat ( - qse_httpd_t* httpd, - qse_httpd_client_t* client, - const qse_mchar_t* fmt, +qse_httpd_task_t* qse_httpd_entaskstatictext ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + 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_t* httpd, - qse_httpd_client_t* client, - qse_ubi_t handle, - qse_foff_t offset, - qse_foff_t size +qse_httpd_task_t* qse_httpd_entaskfile ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + const qse_httpd_task_t* pred, + qse_ubi_t handle, + 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_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 qse_httpd_entaskdisconnect ( - qse_httpd_t* httpd, - qse_httpd_client_t* client +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 ); void* qse_httpd_allocmem ( diff --git a/qse/lib/net/htrd.c b/qse/lib/net/htrd.c index 805b3495..db8b84f0 100644 --- a/qse/lib/net/htrd.c +++ b/qse/lib/net/htrd.c @@ -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) { - 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) @@ -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) { - if (c >= '0' && c <= '9') return c - '0'; + if (c >= QSE_MT('0') && c <= QSE_MT('9')) return c - QSE_MT('0'); return -1; } static QSE_INLINE int xdigit_to_num (qse_mchar_t c) { - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'A' && c <= 'Z') return c - 'A' + 10; - if (c >= 'a' && c <= 'z') return c - 'a' + 10; + if (c >= QSE_MT('0') && c <= QSE_MT('9')) return c - QSE_MT('0'); + if (c >= QSE_MT('A') && c <= QSE_MT('Z')) return c - QSE_MT('A') + 10; + if (c >= QSE_MT('a') && c <= QSE_MT('z')) return c - QSE_MT('a') + 10; return -1; } + static QSE_INLINE int push_to_buffer ( qse_htrd_t* htrd, qse_htob_t* octb, const qse_mchar_t* ptr, qse_size_t len) diff --git a/qse/lib/net/httpd.c b/qse/lib/net/httpd.c index 1253979f..9c3f589c 100644 --- a/qse/lib/net/httpd.c +++ b/qse/lib/net/httpd.c @@ -132,7 +132,8 @@ QSE_INLINE void* qse_httpd_allocmem (qse_httpd_t* httpd, qse_size_t size) 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); 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); } -static int enqueue_task_unlocked ( +static qse_httpd_task_t* enqueue_task_unlocked ( 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; @@ -157,8 +159,9 @@ static int enqueue_task_unlocked ( return -1; } */ - node = qse_httpd_allocmem (httpd, QSE_SIZEOF(*node) + xtnsize); - if (node == QSE_NULL) return -1; + node = (task_queue_node_t*) + qse_httpd_allocmem (httpd, QSE_SIZEOF(*node) + xtnsize); + if (node == QSE_NULL) return QSE_NULL; node->task = *task; @@ -170,43 +173,59 @@ static int enqueue_task_unlocked ( if (httpd->errnum == QSE_HTTPD_ENOERR) httpd->errnum = QSE_HTTPD_ETASK; qse_httpd_freemem (httpd, node); - return -1; + return QSE_NULL; } } - node->next = QSE_NULL; - node->prev = client->task.queue.tail; - if (client->task.queue.tail) + if (pred) { - 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 - { - client->task.queue.head = node; + else + { + 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++; - 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, - 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 (httpd->threaded) { - int ret; + qse_httpd_task_t* ret; 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); return ret; } else { #endif - return enqueue_task_unlocked (httpd, client, task, xtnsize); + return enqueue_task_unlocked (httpd, client, pred, task, xtnsize); #if defined(HAVE_PTHREAD) } #endif @@ -641,7 +660,8 @@ static void perform_task (qse_httpd_t* httpd, qse_httpd_client_t* client) if (n <= -1) { dequeue_task_locked (httpd, client); - shutdown (client->handle.i, SHUT_RDWR); + /*shutdown (client->handle.i, SHUT_RDWR);*/ + client->bad = 1; } else if (n == 0) { @@ -1154,13 +1174,14 @@ void qse_httpd_clearlisteners (qse_httpd_t* httpd) } #endif -int qse_httpd_entask ( +qse_httpd_task_t* qse_httpd_entask ( 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; - ret = enqueue_task_locked (httpd, client, task, xtnsize); - if (ret <= -1) client->bad = 1; /* mark this client bad */ + qse_httpd_task_t* ret; + ret = enqueue_task_locked (httpd, client, pred, task, xtnsize); + if (ret == QSE_NULL) client->bad = 1; /* mark this client bad */ #if defined(HAVE_PTHREAD) else if (httpd->threaded) pthread_cond_signal (&httpd->client.cond); #endif @@ -1174,3 +1195,4 @@ void qse_httpd_markclientbad (qse_httpd_t* httpd, qse_httpd_client_t* client) * like memory allocation failure */ client->bad = 1; } + diff --git a/qse/lib/net/httpd.h b/qse/lib/net/httpd.h index bbbff8b2..bfbab0f8 100644 --- a/qse/lib/net/httpd.h +++ b/qse/lib/net/httpd.h @@ -55,7 +55,7 @@ struct task_queue_node_t { task_queue_node_t* next; task_queue_node_t* prev; - qse_httpd_task_t task; + qse_httpd_task_t task; }; struct qse_httpd_client_t diff --git a/qse/lib/net/httpd_task.c b/qse/lib/net/httpd_task.c index 7ee6fa71..c8644bb1 100644 --- a/qse/lib/net/httpd_task.c +++ b/qse/lib/net/httpd_task.c @@ -28,7 +28,7 @@ #include #include -#define MAX_SENDFILE_SIZE 4096 +#define MAX_SEND_SIZE 4096 #ifdef HAVE_SYS_SENDFILE_H # include @@ -36,7 +36,7 @@ qse_ssize_t sendfile ( 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; if (offset && lseek (in_fd, *offset, SEEK_SET) != *offset) @@ -46,7 +46,7 @@ qse_ssize_t sendfile ( n = read (in_fd, buf, count); 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; return n; @@ -64,14 +64,17 @@ static int task_main_disconnect ( 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_MEMSET (&task, 0, QSE_SIZEOF(task)); 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; 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++; } @@ -105,8 +108,11 @@ static int task_main_statictext ( return 1; /* more work to do */ } -int qse_httpd_entaskstatictext ( - qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_mchar_t* text) +qse_httpd_task_t* qse_httpd_entaskstatictext ( + 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; @@ -114,7 +120,7 @@ int qse_httpd_entaskstatictext ( task.main = task_main_statictext; 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; task_text_t* ctx = (task_text_t*)task->ctx; - count = MAX_SENDFILE_SIZE; + count = MAX_SEND_SIZE; if (count >= ctx->left) count = ctx->left; /* 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 */ } -int qse_httpd_entasktext ( - qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_mchar_t* text) +qse_httpd_task_t* qse_httpd_entasktext ( + 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; task_text_t data; @@ -182,7 +191,7 @@ int qse_httpd_entasktext ( task.ctx = &data; 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; task_format_t* ctx = (task_format_t*)task->ctx; - count = MAX_SENDFILE_SIZE; + count = MAX_SEND_SIZE; if (count >= ctx->left) count = ctx->left; n = send ( @@ -242,8 +251,11 @@ static int task_main_format ( return 1; /* more work to do */ } -int qse_httpd_entaskformat ( - qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_mchar_t* fmt, ...) +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, ...) { qse_httpd_task_t task; task_format_t data; @@ -266,7 +278,7 @@ int qse_httpd_entaskformat ( qse_size_t capa = 256; 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. * thus, it returns -1 when it can't write all the input given. */ @@ -286,7 +298,7 @@ int qse_httpd_entaskformat ( capa = capa * 2; 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; } @@ -297,7 +309,7 @@ int qse_httpd_entaskformat ( * have been written not including the terminating '\0' * if the _data buffer were large enough */ 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); #if defined(_WIN32) && defined(_MSC_VER) @@ -313,7 +325,7 @@ int qse_httpd_entaskformat ( qse_httpd_freemem (httpd, buf); httpd->errnum = QSE_HTTPD_EINTERN; - return -1; + return QSE_NULL; } } @@ -329,7 +341,7 @@ int qse_httpd_entaskformat ( task.ctx = &data; 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 */ @@ -367,7 +379,7 @@ static int task_main_file ( qse_size_t count; task_file_t* ctx = (task_file_t*)task->ctx; - count = MAX_SENDFILE_SIZE; + count = MAX_SEND_SIZE; if (count >= ctx->left) count = ctx->left; /* 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 */ } -int qse_httpd_entaskfile ( - qse_httpd_t* httpd, qse_httpd_client_t* client, - qse_ubi_t handle, qse_foff_t offset, qse_foff_t size) +qse_httpd_task_t* qse_httpd_entaskfile ( + qse_httpd_t* httpd, + 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; task_file_t data; @@ -414,7 +430,7 @@ int qse_httpd_entaskfile ( task.fini = task_fini_file; 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; qse_ubi_t handle; 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); if (handle.i <= -1) { const qse_mchar_t* msg = QSE_MT("Not foundREQUESTED FILE NOT FOUND"); - 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"), data->version.major, data->version.minor, (int)qse_mbslen(msg) + 4, msg ); - goto done; + goto no_file_send; } fcntl (handle.i, F_SETFD, FD_CLOEXEC); @@ -467,12 +485,27 @@ static int task_main_path ( { const qse_mchar_t* msg = QSE_MT("Not foundREQUESTED FILE NOT FOUND"); - 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"), data->version.major, data->version.minor, (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("Directory Listing
  • file1
  • file2
  • file3"); + + 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? */ @@ -494,12 +527,13 @@ static int task_main_path ( const qse_mchar_t* msg; msg = QSE_MT("Requested range not satisfiableREQUESTED RANGE NOT SATISFIABLE"); - 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"), data->version.major, data->version.minor, (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; @@ -512,7 +546,8 @@ static int task_main_path ( } #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"), data->version.major, data->version.minor, @@ -525,7 +560,8 @@ static int task_main_path ( (unsigned long long)st.st_size ); #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"), data->version.major, data->version.minor, @@ -538,14 +574,15 @@ static int task_main_path ( (unsigned long)st.st_size ); #endif - if (x <= -1) goto done; - - x = qse_httpd_entaskfile ( - httpd, client, handle, - data->range.from, - (data->range.to - data->range.from + 1) - ); - if (x <= -1) goto done; + if (x) + { + x = qse_httpd_entaskfile ( + httpd, client, x, + handle, + data->range.from, + (data->range.to - data->range.from + 1) + ); + } } else { @@ -556,11 +593,12 @@ static int task_main_path ( { httpd->errnum = QSE_HTTPD_ENOERR; 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) - 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"), data->version.major, data->version.minor, @@ -570,7 +608,8 @@ static int task_main_path ( data->name ); #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"), data->version.major, data->version.minor, @@ -580,22 +619,26 @@ static int task_main_path ( data->name ); #endif - if (x <= -1) goto done; - - x = qse_httpd_entaskfile (httpd, client, handle, 0, st.st_size); - if (x <= -1) goto done; + if (x) + { + x = qse_httpd_entaskfile ( + 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); - return x; + return (x == QSE_NULL)? -1: 0; } -int qse_httpd_entaskpath ( - qse_httpd_t* httpd, qse_httpd_client_t* client, - const qse_mchar_t* name, const qse_http_range_t* range, +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* verison) { qse_httpd_task_t task; @@ -612,62 +655,142 @@ int qse_httpd_entaskpath ( task.main = task_main_path; 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); } /*------------------------------------------------------------------------*/ -#if 0 -typedef struct httpd_task_cgi_t httpd_task_cgi_t; -struct httpd_task_cgi_t +typedef struct task_cgi_t task_cgi_t; +struct task_cgi_t { + const qse_char_t* path; 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) { - 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)); - xtn->pio = qse_pio_open (httpd->mmgr, task->ctx); - if (xtn->pio == QSE_NULL) - { - httpd->errnum = QSE_HTTPD_ECGI; - return -1; - } - + qse_strcpy ((qse_char_t*)(xtn + 1), task->ctx); + xtn->path = (qse_char_t*)(xtn + 1); task->ctx = xtn; 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) { - httpd_task_cgi_t* xtn = task->ctx; - qse_pio_close (xtn->pio); + task_cgi_t* cgi = (task_cgi_t*)task->ctx; + if (cgi->pio) qse_pio_close (cgi->pio); } - -static void httpd_main_cgi ( +static int task_main_cgi_3 ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) { -/* TODO */ - return -1; + task_cgi_t* cgi = (task_cgi_t*)task->ctx; + 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 ( - qse_httpd_t* httpd, qse_httpd_client_t* client, const qse_char_t* path) +static int task_main_cgi_2 ( + 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; - httpd_task_cgi_t data; QSE_MEMSET (&task, 0, QSE_SIZEOF(task)); - task.init = httpd_init_cgi; - task.main = httpd_main_cgi; - task.fini = httpd_fini_cgi; - task.ctx = path; + task.init = task_init_cgi; + task.fini = task_fini_cgi; + task.main = task_main_cgi; + 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 diff --git a/qse/samples/cmn/pio.c b/qse/samples/cmn/pio.c index 61739912..4c42d77f 100644 --- a/qse/samples/cmn/pio.c +++ b/qse/samples/cmn/pio.c @@ -44,7 +44,7 @@ static int pio1 (const qse_char_t* cmd, int oflags, qse_pio_hid_t rhid) qse_ssize_t i; /*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 <= -1) { diff --git a/qse/samples/net/http01.c b/qse/samples/net/http01.c index 48b3cf06..bce3c49e 100644 --- a/qse/samples/net/http01.c +++ b/qse/samples/net/http01.c @@ -26,6 +26,7 @@ static int handle_request ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req) { int method; + qse_httpd_task_t* x; #if 0 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; qse_http_range_t range; - int x; 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")); +#endif +qse_httpd_entaskcgi (httpd, client, QSE_NULL, QSE_T("/bin/ls -l /etc")); + +#if 0 const qse_mchar_t* msg; msg = QSE_MT("Requested range not satisfiableREQUESTED RANGE NOT SATISFIABLE"); x = qse_httpd_entaskformat (httpd, client, @@ -70,35 +76,42 @@ qse_printf (QSE_T("content = [%.*S]\n"), req->version.major, req->version.minor, (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 { const qse_mchar_t* msg = QSE_MT("Method not allowedREQUEST METHOD NOT ALLOWED"); - 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"), 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 (qse_httpd_entaskdisconnect (httpd, client) <= -1) return -1; + x = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL); + if (x == QSE_NULL) goto oops; } return 0; oops: - qse_httpd_markclientbad (httpd, client); + /*qse_httpd_markclientbad (httpd, client);*/ return 0; }