diff --git a/qse/configure b/qse/configure index 4cec2608..311eecc6 100755 --- a/qse/configure +++ b/qse/configure @@ -17047,6 +17047,34 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t in sys/socket.h" >&5 +$as_echo_n "checking for socklen_t in sys/socket.h... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _POSIX_PII_SOCKET +#include +#include +int +main () +{ +socklen_t x = 5; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define HAVE_SOCKLEN_T 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + QSE_SIZEOF_WCHAR_T=$ac_cv_sizeof_wchar_t QSE_SIZEOF_LONG_LONG=$ac_cv_sizeof_long_long diff --git a/qse/configure.ac b/qse/configure.ac index cb9c8c13..cbb81e29 100644 --- a/qse/configure.ac +++ b/qse/configure.ac @@ -214,6 +214,15 @@ fi AX_PTHREAD() +AC_MSG_CHECKING([for socklen_t in sys/socket.h]) +AC_TRY_COMPILE([#define _POSIX_PII_SOCKET +#include +#include ], [socklen_t x = 5;], + [AC_DEFINE(HAVE_SOCKLEN_T, 1, [Define it socklen_t typedef is in sys/socket.h.]) + AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no)] +) + AC_SUBST(QSE_SIZEOF_WCHAR_T, $ac_cv_sizeof_wchar_t) AC_SUBST(QSE_SIZEOF_LONG_LONG, $ac_cv_sizeof_long_long) AC_SUBST(QSE_SIZEOF_LONG, $ac_cv_sizeof_long) diff --git a/qse/include/qse/config.h.in b/qse/include/qse/config.h.in index f1e37361..b1f6a657 100644 --- a/qse/include/qse/config.h.in +++ b/qse/include/qse/config.h.in @@ -126,6 +126,9 @@ /* Define to 1 if you have the `sinl' function. */ #undef HAVE_SINL +/* Define it socklen_t typedef is in sys/socket.h. */ +#undef HAVE_SOCKLEN_T + /* Define to 1 if you have the `sqrt' function. */ #undef HAVE_SQRT diff --git a/qse/include/qse/net/htrd.h b/qse/include/qse/net/htrd.h index 53477794..26e3a2f5 100644 --- a/qse/include/qse/net/htrd.h +++ b/qse/include/qse/net/htrd.h @@ -53,7 +53,6 @@ struct qse_htrd_recbs_t int (*request) (qse_htrd_t* htrd, qse_htre_t* req); int (*expect_continue) (qse_htrd_t* htrd, qse_htre_t* req); int (*response) (qse_htrd_t* htrd, qse_htre_t* res); - int (*qparamstr) (qse_htrd_t* htrd, const qse_mcstr_t* key, const qse_mcstr_t* val); }; struct qse_htrd_t @@ -92,12 +91,14 @@ struct qse_htrd_t void* chl; } fed; +#if 0 struct { /* temporary space to store a key and value pair * during the call to qse_http_scanqparamstr() */ qse_htob_t qparam; } tmp; +#endif enum { diff --git a/qse/include/qse/net/httpd.h b/qse/include/qse/net/httpd.h index 6a8168ce..ff9f98e2 100644 --- a/qse/include/qse/net/httpd.h +++ b/qse/include/qse/net/httpd.h @@ -46,6 +46,15 @@ typedef enum qse_httpd_errnum_t qse_httpd_errnum_t; typedef struct qse_httpd_cbs_t qse_httpd_cbs_t; struct qse_httpd_cbs_t { + struct + { + const qse_mchar_t* (*getmimetype) (qse_httpd_t* httpd, const qse_mchar_t* path); + + qse_ubi_t (*open) (qse_httpd_t* httpd, const qse_mchar_t* path); + void (*close) (qse_httpd_t* httpd, qse_ubi_t handle); + int (*getsize) (qse_httpd_t* httpd, qse_ubi_t handle, qse_foff_t* size); + } file; + int (*handle_request) ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req); int (*handle_expect_continue) ( diff --git a/qse/lib/net/htrd.c b/qse/lib/net/htrd.c index b3f2e6da..805b3495 100644 --- a/qse/lib/net/htrd.c +++ b/qse/lib/net/htrd.c @@ -173,7 +173,9 @@ qse_htrd_t* qse_htrd_init (qse_htrd_t* htrd, qse_mmgr_t* mmgr) htrd->mmgr = mmgr; htrd->option = QSE_HTRD_REQUEST | QSE_HTRD_RESPONSE; +#if 0 qse_mbs_init (&htrd->tmp.qparam, htrd->mmgr, 0); +#endif qse_mbs_init (&htrd->fed.b.raw, htrd->mmgr, 0); qse_mbs_init (&htrd->fed.b.tra, htrd->mmgr, 0); @@ -181,7 +183,9 @@ qse_htrd_t* qse_htrd_init (qse_htrd_t* htrd, qse_mmgr_t* mmgr) { qse_mbs_fini (&htrd->fed.b.tra); qse_mbs_fini (&htrd->fed.b.raw); +#if 0 qse_mbs_fini (&htrd->tmp.qparam); +#endif return QSE_NULL; } @@ -195,7 +199,9 @@ void qse_htrd_fini (qse_htrd_t* htrd) clear_combined_headers (htrd); qse_mbs_fini (&htrd->fed.b.tra); qse_mbs_fini (&htrd->fed.b.raw); +#if 0 qse_mbs_fini (&htrd->tmp.qparam); +#endif } static qse_mchar_t* parse_initial_line ( @@ -1307,6 +1313,7 @@ feedme_more: return 0; } +#if 0 int qse_htrd_scanqparam (qse_htrd_t* htrd, const qse_mcstr_t* cstr) { qse_mcstr_t key, val; @@ -1412,3 +1419,4 @@ int qse_htrd_scanqparam (qse_htrd_t* htrd, const qse_mcstr_t* cstr) qse_mbs_clear (&htrd->tmp.qparam); return 0; } +#endif diff --git a/qse/lib/net/httpd.c b/qse/lib/net/httpd.c index 5ac89baa..1253979f 100644 --- a/qse/lib/net/httpd.c +++ b/qse/lib/net/httpd.c @@ -53,18 +53,6 @@ QSE_IMPLEMENT_COMMON_FUNCTIONS (httpd) static void free_listener_list (qse_httpd_t* httpd, listener_t* l); -static int handle_request ( - qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req); -static int handle_expect_continue ( - qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req); - -static qse_httpd_cbs_t default_cbs = -{ - handle_request, - handle_expect_continue -}; - - qse_httpd_t* qse_httpd_open (qse_mmgr_t* mmgr, qse_size_t xtnsize) { qse_httpd_t* httpd; @@ -104,7 +92,6 @@ qse_httpd_t* qse_httpd_init (qse_httpd_t* httpd, qse_mmgr_t* mmgr) QSE_MEMSET (httpd, 0, QSE_SIZEOF(*httpd)); httpd->mmgr = mmgr; httpd->listener.max = -1; - httpd->cbs = &default_cbs; #if defined(HAVE_PTHREAD) pthread_mutex_init (&httpd->listener.mutex, QSE_NULL); @@ -283,186 +270,6 @@ static void purge_tasks_locked (qse_httpd_t* httpd, qse_httpd_client_t* client) #endif } -static int capture_param (qse_htrd_t* http, const qse_mcstr_t* key, const qse_mcstr_t* val) -{ -qse_printf (QSE_T("PARAM %d[%S] => %d[%S] \n"), (int)key->len, key->ptr, (int)val->len, val->ptr); - return 0; -} - -static int handle_request (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req) -{ -#if 0 - int method; - - method = qse_htre_getqmethod (req); - - if (method == QSE_HTTP_GET || method == QSE_HTTP_POST) - { - int fd; - -#if 0 - /*if (qse_htrd_scanqparam (http, qse_htre_getqparamcstr(req)) <= -1) */ - if (qse_htrd_scanqparam (http, QSE_NULL) <= -1) - { -const char* msg = "INTERNAL SERVER ERRORINTERNAL SERVER ERROR"; -char* text = format_textdup (xtn->httpd, - "HTTP/%d.%d 500 Internal Server Error\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n", - req->version.major, - req->version.minor, - (int)strlen(msg) + 4, msg); -if (text == QSE_NULL || enqueue_sendduptext_locked (httpd, client, text) <= -1) -{ - if (text) httpd_free (xtn->httpd, text); - qse_printf (QSE_T("failed to format text push task....\n")); - return -1; -} - - } -#endif - -#if 0 - if (method == QSE_HTTP_POST) - { - if (qse_htrd_scanqparam (http, qse_htre_getcontentcstr(req)) <= -1) - { - } - } -#endif - - fd = open (qse_htre_getqpathptr(req), O_RDONLY); - if (fd <= -1) - { - const char* msg = "NOT FOUNDREQUESTD FILE NOT FOUND"; - char* text = format_textdup ( - httpd, - "HTTP/%d.%d 404 Not found\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n", - req->version.major, - req->version.minor, - (int)strlen(msg) + 4, msg - ); - - if (text == QSE_NULL || enqueue_sendduptext_locked (httpd, client, text) <= -1) - { - if (text) httpd_free (httpd, text); - qse_printf (QSE_T("failed to push task....\n")); - return -1; - } - } - else - { - struct stat st; - if (fstat (fd, &st) <= -1) - { - close (fd); - -qse_printf (QSE_T("fstat failure....\n")); - } - else if (st.st_size <= 0) - { - close (fd); -qse_printf (QSE_T("empty file....\n")); - } - else - { - -char text[128]; -snprintf (text, QSE_SIZEOF(text), - "HTTP/%d.%d 200 OK\r\nContent-Length: %llu\r\nContent-Location: %s\r\n\r\n", - qse_htre_getmajorversion(req), - qse_htre_getminorversion(req), - (unsigned long long)st.st_size, - qse_htre_getqpathptr(req) -); - - if (enqueue_sendtextdup_locked (httpd, client, text) <= -1) - { -qse_printf (QSE_T("failed to push task....\n")); - return -1; - } - - if (enqueue_sendfile_locked (httpd, client, fd) <= -1) - { - /* TODO: close??? just close....??? */ -qse_printf (QSE_T("failed to push task....\n")); - return -1; - } - - } - } - } - else - { -char text[256]; -const char* msg = "Method not allowedMETHOD NOT ALLOWED"; -snprintf (text, QSE_SIZEOF(text), - "HTTP/%d.%d 405 Method not allowed\r\nContent-Length: %d\r\n\r\n%s\r\n\r\n", - qse_htre_getmajorversion(req), - qse_htre_getminorversion(req), - (int)strlen(msg)+4, msg); -if (enqueue_sendtextdup_locked (httpd, client, text) <= -1) -{ -qse_printf (QSE_T("failed to push task....\n")); -return -1; -} - } - - if (req->attr.connection_close) - { - if (enqueue_disconnect (httpd, client) <= -1) - { -qse_printf (QSE_T("failed to push task....\n")); - return -1; - } - } - - return 0; -#endif - -return 0; -} - - -static int handle_expect_continue (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req) -{ -#if 0 -/* - htrd_xtn_t* xtn = (htrd_xtn_t*) qse_htrd_getxtn (http); - qse_httpd_client_t* client = &xtn->array->data[xtn->index]; -*/ - -/* TODO: change this whole callback */ - if (qse_htre_getqmethod(req) == QSE_HTTP_POST) - { - qse_mchar_t text[32]; - - snprintf (text, QSE_SIZEOF(text), - QSE_MT("HTTP/%d.%d 100 OK\r\n\r\n"), - req->version.major, req->version.minor); - - if (enqueue_sendtextdup_locked (httpd, client, text) <= -1) - { - return -1; - } - } - else - { - qse_mchar_t text[32]; - - qse_htre_setdiscard (req, 1); - - snprintf (text, QSE_SIZEOF(text), - QSE_MT("HTTP/%d.%d 404 Not found\r\n\r\n"), - req->version.major, req->version.minor); - - if (enqueue_sendtextdup_locked (httpd, client, text) <= -1) - { - return -1; - } - } -#endif - return 0; -} - static int htrd_handle_request (qse_htrd_t* htrd, qse_htre_t* req) { htrd_xtn_t* xtn = (htrd_xtn_t*) qse_htrd_getxtn (htrd); @@ -477,31 +284,13 @@ static int htrd_handle_expect_continue (qse_htrd_t* htrd, qse_htre_t* req) return xtn->httpd->cbs->handle_expect_continue (xtn->httpd, client, req); } -static int htrd_handle_response (qse_htrd_t* htrd, qse_htre_t* res) -{ -/* - htrd_xtn_t* xtn = (htrd_xtn_t*) qse_htrd_getxtn (htrd); - qse_httpd_client_t* client = &xtn->httpd->client.array.data[xtn->client_index]; -*/ - -/* directly send some response saying stupid request... */ - qse_printf (QSE_T("response received... HTTP/%d.%d %d %.*S\n"), - qse_htre_getmajorversion(res), - qse_htre_getminorversion(res), - qse_htre_getsstatus(res), - (int)qse_htre_getsmessagelen(res), - qse_htre_getsmessageptr(res) - ); - - return 0; -} - static qse_htrd_recbs_t htrd_recbs = { htrd_handle_request, htrd_handle_expect_continue, - htrd_handle_response, - capture_param + + /* The response handler is not needed as QSE_HTRD_RESPONSE is truned off */ + QSE_NULL }; static void deactivate_listener (qse_httpd_t* httpd, listener_t* l) @@ -997,6 +786,10 @@ int qse_httpd_loop (qse_httpd_t* httpd, int threaded) "Add listeners before calling qse_httpd_loop()" ); + QSE_ASSERTX (httpd->cbs != QSE_NULL, + "Set httpd callbacks before calling qse_httpd_loop()" + ); + if (httpd->listener.list == QSE_NULL) { /* no listener specified */ diff --git a/qse/lib/net/httpd_task.c b/qse/lib/net/httpd_task.c index a920ee63..7ee6fa71 100644 --- a/qse/lib/net/httpd_task.c +++ b/qse/lib/net/httpd_task.c @@ -459,8 +459,9 @@ static int task_main_path ( data->version.major, data->version.minor, (int)qse_mbslen(msg) + 4, msg ); - if (x <= -1) return -1; + goto done; } + fcntl (handle.i, F_SETFD, FD_CLOEXEC); if (fstat (handle.i, &st) <= -1) { @@ -471,13 +472,15 @@ static int task_main_path ( data->version.major, data->version.minor, (int)qse_mbslen(msg) + 4, msg ); - if (x <= -1) goto oops; + goto done; } if (st.st_size < 0) st.st_size = 0; /* can this happen? */ if (data->range.type != QSE_HTTP_RANGE_NONE) { + const qse_mchar_t* mime_type = QSE_NULL; + if (data->range.type == QSE_HTTP_RANGE_SUFFIX) { if (data->range.to > st.st_size) data->range.to = st.st_size; @@ -496,16 +499,25 @@ static int task_main_path ( data->version.major, data->version.minor, (int)qse_mbslen(msg) + 4, msg ); - if (x <= -1) goto oops; + goto done; } if (data->range.to >= st.st_size) data->range.to = st.st_size - 1; + if (httpd->cbs->file.getmimetype) + { + httpd->errnum = QSE_HTTPD_ENOERR; + mime_type = httpd->cbs->file.getmimetype (httpd, data->name); + /*TODO: how to handle an error... */ + } + #if (QSE_SIZEOF_LONG_LONG > 0) x = qse_httpd_entaskformat (httpd, client, - QSE_MT("HTTP/%d.%d 206 Partial content\r\nContent-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.minor, + (mime_type? QSE_MT("\r\nContent-Type: "): QSE_MT("")), + (mime_type? mime_type: QSE_MT("")), (unsigned long long)(data->range.to - data->range.from + 1), data->name, (unsigned long long)data->range.from, @@ -514,9 +526,11 @@ static int task_main_path ( ); #else x = qse_httpd_entaskformat (httpd, client, - QSE_MT("HTTP/%d.%d 206 Partial content\r\nContent-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.minor, + (mime_type? QSE_MT("\r\nContent-Type: "): QSE_MT("")), + (mime_type? mime_type: QSE_MT("")), (unsigned long)(data->range.to - data->range.from + 1), data->name, (unsigned long)data->range.from, @@ -524,47 +538,59 @@ static int task_main_path ( (unsigned long)st.st_size ); #endif - if (x <= -1) goto oops; + 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 oops; + if (x <= -1) goto done; } else { /* TODO: int64 format.... don't hard code it llu */ + const qse_mchar_t* mime_type = QSE_NULL; + + if (httpd->cbs->file.getmimetype) + { + httpd->errnum = QSE_HTTPD_ENOERR; + mime_type = httpd->cbs->file.getmimetype (httpd, data->name); + /*TODO: how to handle an error... */ + } #if (QSE_SIZEOF_LONG_LONG > 0) x = qse_httpd_entaskformat (httpd, client, - QSE_MT("HTTP/%d.%d 200 OK\r\nContent-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.minor, + (mime_type? QSE_MT("\r\nContent-Type: "): QSE_MT("")), + (mime_type? mime_type: QSE_MT("")), (unsigned long long)st.st_size, data->name ); #else x = qse_httpd_entaskformat (httpd, client, - QSE_MT("HTTP/%d.%d 200 OK\r\nContent-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.minor, + (mime_type? QSE_MT("\r\nContent-Type: "): QSE_MT("")), + (mime_type? mime_type: QSE_MT("")), (unsigned long)st.st_size, data->name ); #endif - if (x <= -1) goto oops; + if (x <= -1) goto done; x = qse_httpd_entaskfile (httpd, client, handle, 0, st.st_size); - if (x <= -1) goto oops; + if (x <= -1) goto done; } return 0; -oops: - close (handle.i); - return -1; +done: + if (handle.i >= 0) close (handle.i); + return x; } int qse_httpd_entaskpath ( diff --git a/qse/samples/net/http01.c b/qse/samples/net/http01.c index 11be3b18..48b3cf06 100644 --- a/qse/samples/net/http01.c +++ b/qse/samples/net/http01.c @@ -118,6 +118,7 @@ static void sigint (int sig) static qse_httpd_cbs_t httpd_cbs = { + { QSE_NULL }, handle_request, handle_expect_continue };