diff --git a/qse/include/qse/cmn/nwad.h b/qse/include/qse/cmn/nwad.h index 1ed77cfe..bb483360 100644 --- a/qse/include/qse/cmn/nwad.h +++ b/qse/include/qse/cmn/nwad.h @@ -75,6 +75,11 @@ enum qse_nwadtostr_flag_t extern "C" { #endif +int qse_nwadequal ( + const qse_nwad_t* x, + const qse_nwad_t* y +); + int qse_mbstonwad ( const qse_mchar_t* mbs, qse_nwad_t* nwad diff --git a/qse/include/qse/net/httpd.h b/qse/include/qse/net/httpd.h index c5fc5233..82e36ddd 100644 --- a/qse/include/qse/net/httpd.h +++ b/qse/include/qse/net/httpd.h @@ -310,9 +310,6 @@ struct qse_httpd_client_t qse_httpd_client_t* bad_next; - qse_httpd_client_t* prev_tasked; - qse_httpd_client_t* next_tasked; - struct { int count; @@ -362,7 +359,10 @@ struct qse_httpd_rsrc_t const qse_mchar_t* path; } dir; - int error; + struct + { + int code; + } error; struct { @@ -713,7 +713,10 @@ void* qse_httpd_getserverxtnstd ( qse_httpd_t* httpd, qse_httpd_server_t* server ); - + +qse_httpd_cbstd_t* qse_httpd_getdflcbstd ( + qse_httpd_t* httpd +); int qse_httpd_loopstd ( qse_httpd_t* httpd, diff --git a/qse/lib/cmn/nwad.c b/qse/lib/cmn/nwad.c index 8c4b18ec..08cdec16 100644 --- a/qse/lib/cmn/nwad.c +++ b/qse/lib/cmn/nwad.c @@ -25,6 +25,27 @@ #include #include "mem.h" +int qse_nwadequal (const qse_nwad_t* x, const qse_nwad_t* y) +{ + if (x->type != y->type) return 0; + + switch (x->type) + { + case QSE_NWAD_IN4: + return (x->u.in4.port == y->u.in4.port && + QSE_MEMCMP (&x->u.in4.addr, &y->u.in4.addr, QSE_SIZEOF(x->u.in4.addr)) == 0)? 1: 0; + + case QSE_NWAD_IN6: + return (x->u.in6.port == y->u.in6.port && + x->u.in6.scope == y->u.in6.scope && + QSE_MEMCMP (&x->u.in6.addr, &y->u.in6.addr, QSE_SIZEOF(x->u.in6.addr)) == 0)? 1: 0; + + default: + /* can't compare */ + return -1; + } +} + int qse_mbstonwad (const qse_mchar_t* str, qse_nwad_t* nwad) { return qse_mbsntonwad (str, qse_mbslen(str), nwad); diff --git a/qse/lib/net/httpd-std.c b/qse/lib/net/httpd-std.c index 88d230cb..91f21d0f 100644 --- a/qse/lib/net/httpd-std.c +++ b/qse/lib/net/httpd-std.c @@ -337,10 +337,6 @@ static int init_xtn_ssl ( { SSL_CTX* ctx; - SSL_library_init (); - SSL_load_error_strings (); - /*SSLeay_add_ssl_algorithms();*/ - ctx = SSL_CTX_new (SSLv23_server_method()); if (ctx == QSE_NULL) return -1; @@ -353,14 +349,15 @@ static int init_xtn_ssl ( { qse_mchar_t buf[128]; ERR_error_string_n(ERR_get_error(), buf, QSE_COUNTOF(buf)); - qse_fprintf (QSE_STDERR, QSE_T("Error: %hs\n"), buf); +/* TODO: logging */ +qse_fprintf (QSE_STDERR, QSE_T("Error: %hs\n"), buf); SSL_CTX_free (ctx); return -1; } -/* TODO: CRYPTO_set_id_callback (); - TODO: CRYPTO_set_locking_callback ();*/ + /* TODO: CRYPTO_set_id_callback (); */ + /* TODO: CRYPTO_set_locking_callback (); */ SSL_CTX_set_read_ahead (ctx, 0); xtn->ssl_ctx = ctx; @@ -369,16 +366,9 @@ static int init_xtn_ssl ( static void fini_xtn_ssl (httpd_xtn_t* xtn) { -/* TODO: CRYPTO_set_id_callback (QSE_NULL); - TODO: CRYPTO_set_locking_callback (QSE_NULL); */ + /* TODO: CRYPTO_set_id_callback (QSE_NULL); */ + /* TODO: CRYPTO_set_locking_callback (QSE_NULL); */ SSL_CTX_free (xtn->ssl_ctx); - - /*ERR_remove_state ();*/ - ENGINE_cleanup (); - - ERR_free_strings (); - EVP_cleanup (); - CRYPTO_cleanup_all_ex_data (); } #endif @@ -464,11 +454,11 @@ qse_httpd_server_t* qse_httpd_attachserverstd ( if (qse_strtouri (uri, &xuri, QSE_STRTOURI_NOQUERY) <= -1) goto invalid; - if (qse_strxcmp (xuri.scheme.ptr, xuri.scheme.len, QSE_T("http")) == 0) + if (qse_strxcasecmp (xuri.scheme.ptr, xuri.scheme.len, QSE_T("http")) == 0) { default_port = DEFAULT_PORT; } - else if (qse_strxcmp (xuri.scheme.ptr, xuri.scheme.len, QSE_T("https")) == 0) + else if (qse_strxcasecmp (xuri.scheme.ptr, xuri.scheme.len, QSE_T("https")) == 0) { server.flags |= QSE_HTTPD_SERVER_SECURE; default_port = DEFAULT_SECURE_PORT; @@ -1540,7 +1530,7 @@ if (qse_htre_getqparam(req)) qse_htb_walk (&req->hdrtab, walk, QSE_NULL); if (qse_htre_getcontentlen(req) > 0) { - qse_printf (QSE_T("CONTENT before discard = [%.*S]\n"), (int)qse_htre_getcontentlen(req), qse_htre_getcontentptr(req)); + qse_printf (QSE_T("CONTENT [%.*S]\n"), (int)qse_htre_getcontentlen(req), qse_htre_getcontentptr(req)); } if (peek) @@ -1562,21 +1552,11 @@ if (qse_htre_getcontentlen(req) > 0) * and no content received yet */ /* TODO: determine if to return 100-continue or other errors */ -{ -qse_ntime_t now; -qse_gettime (&now); -qse_printf (QSE_T("entasking continue at %lld\n"), (long long)now); -} if (qse_httpd_entaskcontinue ( httpd, client, QSE_NULL, req) == QSE_NULL) return -1; } } -if (qse_htre_getcontentlen(req) > 0) -{ - qse_printf (QSE_T("CONTENT after discard = [%.*S]\n"), (int)qse_htre_getcontentlen(req), qse_htre_getcontentptr(req)); -} - if (method == QSE_HTTP_GET || method == QSE_HTTP_POST) { if (peek) @@ -1638,81 +1618,16 @@ oops: return -1; } -static int proxy_request ( - qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, int peek) -{ - qse_httpd_task_t* task; - - /* TODO: investigate if the proxy need to handle 100-continue */ - - if (peek) - { - qse_nwad_t nwad; - -#if 0 - if (qse_nwadequal (&client->local_addr, &client->orgdst_addr)) - { - //qse_strtonwad (QSE_T("192.168.1.55:9000"), &nwad); - //qse_strtonwad (QSE_T("1.234.53.142:80"), &nwad); - } - else - { -#endif - nwad = client->orgdst_addr; -#if 0 - } -#endif - task = qse_httpd_entaskproxy (httpd, client, QSE_NULL, &nwad, QSE_NULL, req); - if (task == QSE_NULL) goto oops; - } - - if (!(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)) - { - if (!peek) - { - task = qse_httpd_entaskdisconnect (httpd, client, QSE_NULL); - if (task == QSE_NULL) goto oops; - } - } - - return 0; - -oops: - return -1; -} - static int peek_request ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req) { -/* - if (QSE_MEMCMP (&client->local_addr, &client->orgdst_addr, sizeof(client->orgdst_addr)) == 0) - { -*/ - return process_request (httpd, client, req, 1); -/* - } - else - { - return proxy_request (httpd, client, req, 1); - } -*/ + return process_request (httpd, client, req, 1); } static int handle_request ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req) { -/* - if (QSE_MEMCMP (&client->local_addr, &client->orgdst_addr, sizeof(client->orgdst_addr)) == 0) - { -*/ - return process_request (httpd, client, req, 0); -/* - } - else - { - return proxy_request (httpd, client, req, 0); - } -*/ + return process_request (httpd, client, req, 0); } static qse_httpd_scb_t httpd_system_callbacks = @@ -1973,6 +1888,11 @@ static qse_httpd_cbstd_t httpd_cbstd = free_resource }; +qse_httpd_cbstd_t* qse_httpd_getdflcbstd (qse_httpd_t* httpd) +{ + return &httpd_cbstd; +} + int qse_httpd_loopstd (qse_httpd_t* httpd, qse_httpd_cbstd_t* cbstd, qse_ntime_t timeout) { httpd_xtn_t* xtn; diff --git a/qse/lib/net/httpd-task.c b/qse/lib/net/httpd-task.c index 7d93afb8..b537617f 100644 --- a/qse/lib/net/httpd-task.c +++ b/qse/lib/net/httpd-task.c @@ -395,7 +395,8 @@ qse_httpd_task_t* qse_httpd_entaskrsrc ( case QSE_HTTPD_RSRC_ERROR: qse_httpd_discardcontent (httpd, req); - task = qse_httpd_entaskerror (httpd, client, QSE_NULL, rsrc->u.error, req); + task = qse_httpd_entaskerror (httpd, client, QSE_NULL, rsrc->u.error.code, req); + break; case QSE_HTTPD_RSRC_FILE: qse_httpd_discardcontent (httpd, req); diff --git a/qse/lib/net/httpd.c b/qse/lib/net/httpd.c index 61199c04..1807449b 100644 --- a/qse/lib/net/httpd.c +++ b/qse/lib/net/httpd.c @@ -350,26 +350,16 @@ static void purge_client (qse_httpd_t* httpd, qse_httpd_client_t* client) { qse_httpd_client_t* prev; qse_httpd_client_t* next; - qse_httpd_client_t* prev_tasked; - qse_httpd_client_t* next_tasked; prev = client->prev; next = client->next; - prev_tasked = client->prev_tasked; - next_tasked = client->next_tasked; - free_client (httpd, client); if (prev) prev->next = next; else httpd->client.list.head = next; if (next) next->prev = prev; else httpd->client.list.tail = prev; - - if (prev_tasked) prev_tasked->next_tasked = next_tasked; - else httpd->client.tasked.head = next_tasked; - if (next_tasked) next_tasked->prev_tasked = prev_tasked; - else httpd->client.tasked.tail = prev_tasked; } static void purge_client_list (qse_httpd_t* httpd) @@ -474,44 +464,6 @@ qse_printf (QSE_T("connection %d accepted %s(%s from %s\n"), client->handle.i, t return 0; } -static void insert_client_to_tasked_list ( - qse_httpd_t* httpd, qse_httpd_client_t* client) -{ - QSE_ASSERT (client->prev_tasked == QSE_NULL); - QSE_ASSERT (client->next_tasked == QSE_NULL); - - if (httpd->client.tasked.tail) - { - QSE_ASSERT (httpd->client.tasked.head); - client->prev_tasked = httpd->client.tasked.tail; - httpd->client.tasked.tail->next_tasked = client; - httpd->client.tasked.tail = client; - } - else - { - httpd->client.tasked.head = client; - httpd->client.tasked.tail = client; - } -} - -static void delete_client_from_tasked_list ( - qse_httpd_t* httpd, qse_httpd_client_t* client) -{ - qse_httpd_client_t* prev_tasked; - qse_httpd_client_t* next_tasked; - - prev_tasked = client->prev_tasked; - next_tasked = client->next_tasked; - - if (prev_tasked) prev_tasked->next_tasked = next_tasked; - else httpd->client.tasked.head = next_tasked; - if (next_tasked) next_tasked->prev_tasked = prev_tasked; - else httpd->client.tasked.tail = prev_tasked; - - client->prev_tasked = QSE_NULL; - client->next_tasked = QSE_NULL; -} - /* --------------------------------------------------- */ static void deactivate_servers (qse_httpd_t* httpd) @@ -1096,9 +1048,6 @@ qse_httpd_task_t* qse_httpd_entask ( } else if (new_task->prev == QSE_NULL) { - /* this new task is the first task for a client */ - /*insert_client_to_tasked_list (httpd, client);*/ - /* arrange to invokde this task so long as * the client-side handle is writable. */ QSE_ASSERT (client->status & CLIENT_HANDLE_IN_MUX); diff --git a/qse/samples/net/httpd01.c b/qse/samples/net/httpd01.c index fd1ca9fa..48655f60 100644 --- a/qse/samples/net/httpd01.c +++ b/qse/samples/net/httpd01.c @@ -26,6 +26,12 @@ # include #endif +#if defined(HAVE_SSL) +# include +# include +# include +#endif + static qse_httpd_t* g_httpd = QSE_NULL; static void sigint (int sig) @@ -81,9 +87,14 @@ oops: int qse_main (int argc, qse_achar_t* argv[]) { + int ret; + #if defined(_WIN32) char locale[100]; - UINT codepage = GetConsoleOutputCP(); + UINT codepage; + WSADATA wsadata; + + codepage = GetConsoleOutputCP(); if (codepage == CP_UTF8) { /*SetConsoleOUtputCP (CP_UTF8);*/ @@ -95,11 +106,37 @@ int qse_main (int argc, qse_achar_t* argv[]) setlocale (LC_ALL, locale); qse_setdflcmgrbyid (QSE_CMGR_SLMB); } + + if (WSAStartup (MAKEWORD(2,0), &wsadata) != 0) + { + qse_fprintf (QSE_STDERR, QSE_T("Failed to start up winsock\n")); + return -1; + } + #else setlocale (LC_ALL, ""); qse_setdflcmgrbyid (QSE_CMGR_SLMB); #endif - return qse_runmain (argc, argv, httpd_main); +#if defined(HAVE_SSL) + SSL_load_error_strings (); + SSL_library_init (); +#endif + + ret = qse_runmain (argc, argv, httpd_main); + +#if defined(HAVE_SSL) + /*ERR_remove_state ();*/ + ENGINE_cleanup (); + ERR_free_strings (); + EVP_cleanup (); + CRYPTO_cleanup_all_ex_data (); +#endif + +#if defined(_WIN32) + WSACleanup (); +#endif + + return ret; } diff --git a/qse/samples/net/httpd02.c b/qse/samples/net/httpd02.c index 1c7e8f2c..524dacf8 100644 --- a/qse/samples/net/httpd02.c +++ b/qse/samples/net/httpd02.c @@ -27,22 +27,83 @@ #endif +#if defined(HAVE_SSL) +# include +# include +# include +#endif + /* --------------------------------------------------------------------- */ -typedef struct xtn_t xtn_t; -struct xtn_t +typedef struct server_xtn_t server_xtn_t; +struct server_xtn_t { - qse_mchar_t basedir[4096]; + int tproxy; }; static int makersrc ( qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, qse_httpd_rsrc_t* rsrc) { - return -1; + server_xtn_t* server_xtn; + + server_xtn = qse_httpd_getserverxtnstd (httpd, client->server); + + if (server_xtn->tproxy) + { + if (qse_nwadequal(&client->orgdst_addr, &client->local_addr)) /* both equal and error */ + { + /* TODO: implement a better check that the + * destination is not one of the local addresses */ + + rsrc->type = QSE_HTTPD_RSRC_ERROR; + rsrc->u.error.code = 500; + } + else + { + rsrc->type = QSE_HTTPD_RSRC_PROXY; + rsrc->u.proxy.dst = client->orgdst_addr; + rsrc->u.proxy.src = client->remote_addr; + + if (rsrc->u.proxy.src.type == QSE_NWAD_IN4) + rsrc->u.proxy.src.u.in4.port = 0; /* reset the port to 0. */ + else if (rsrc->u.proxy.src.type == QSE_NWAD_IN6) + rsrc->u.proxy.src.u.in6.port = 0; /* reset the port to 0. */ + } + + return 0; + } + else + { + qse_httpd_cbstd_t* dflcbstd = qse_httpd_getdflcbstd (httpd); +#if 0 + if (dflcbstd->makersrc (httpd, client, req, rsrc) <= -1) return -1; + if (rsrc->type == QSE_HTTPD_RSRC_DIR) + { + /* no directory listing - */ + rsrc->type = QSE_HTTPD_RSRC_ERROR; + rsrc->u.error.code = 500; + } + return 0; +#endif + return dflcbstd->makersrc (httpd, client, req, rsrc); + } } -static void freersrc (qse_httpd_t* httpd, qse_httpd_rsrc_t* rsrc) +static void freersrc (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_htre_t* req, qse_httpd_rsrc_t* rsrc) { + server_xtn_t* server_xtn; + + server_xtn = qse_httpd_getserverxtnstd (httpd, client->server); + + if (server_xtn->tproxy) + { + /* nothing to do */ + } + else + { + qse_httpd_cbstd_t* dflcbstd = qse_httpd_getdflcbstd (httpd); + return dflcbstd->freersrc (httpd, client, req, rsrc); + } } /* --------------------------------------------------------------------- */ @@ -55,46 +116,26 @@ static void sigint (int sig) } /* --------------------------------------------------------------------- */ -#if 0 -static qse_httpd_server_t* attach_server (qse_httpd_t* httpd, const qse_char_t* uri) +static qse_httpd_server_t* attach_server (qse_httpd_t* httpd, qse_char_t* uri) { - qse_httpd_server_t server, * xserver; - const qse_char_t* docroot; + qse_httpd_server_t* server; server_xtn_t* server_xtn; - qse_uri_t xuri; + int tproxy = 0; - if (qse_ripuri (uri, &xuri, QSE_RIPURI_NOQUERY | QSE_RIP_URI_NOFRAGMENT) <= -1) - return QSE_NULL; - -/* if (parse_server_uri (httpd, uri, &server, &docroot) <= -1) return QSE_NULL;*/ - server.predetach = predetach_server; - - xserver = qse_httpd_attachserver ( - httpd, &server, QSE_SIZEOF(*server_xtn) + xtnsize); - if (xserver == QSE_NULL) return QSE_NULL; - - if (docroot[0] == QSE_T('/') && docroot[1] != QSE_T('\0')) + if (qse_strzcasecmp (uri, QSE_T("http-tproxy://"), 14) == 0) { - server_xtn = qse_httpd_getserverxtn (httpd, xserver); - -#if defined(QSE_CHAR_IS_MCHAR) - server_xtn->docroot.ptr = qse_mbsdup (docroot, httpd->mmgr); -#else - server_xtn->docroot.ptr = qse_wcstombsdup (docroot, httpd->mmgr); -#endif - if (server_xtn->docroot.ptr == QSE_NULL) - { - qse_httpd_detachserver (httpd, xserver); - httpd->errnum = QSE_HTTPD_ENOMEM; - return QSE_NULL; - } - - server_xtn->docroot.len = qse_mbslen(server_xtn->docroot.ptr); + tproxy = 1; + qse_strcpy (&uri[4], &uri[11]); } - return xserver; + server = qse_httpd_attachserverstd (httpd, uri, QSE_SIZEOF(server_xtn_t)); + if (server == QSE_NULL) return QSE_NULL; + + server_xtn = qse_httpd_getserverxtnstd (httpd, server); + server_xtn->tproxy = tproxy; + + return server; } -#endif /* --------------------------------------------------------------------- */ static int httpd_main (int argc, qse_char_t* argv[]) @@ -109,7 +150,7 @@ static int httpd_main (int argc, qse_char_t* argv[]) goto oops; } - httpd = qse_httpd_openstd (QSE_SIZEOF(xtn_t)); + httpd = qse_httpd_openstd (QSE_SIZEOF(server_xtn_t)); if (httpd == QSE_NULL) { qse_fprintf (QSE_STDERR, QSE_T("Cannot open httpd\n")); @@ -118,7 +159,7 @@ static int httpd_main (int argc, qse_char_t* argv[]) for (i = 1; i < argc; i++) { - if (qse_httpd_attachserverstd (httpd, argv[i], 0) == QSE_NULL) + if (attach_server (httpd, argv[i]) == QSE_NULL) { qse_fprintf (QSE_STDERR, QSE_T("Failed to add httpd listener - %s\n"), argv[i]); @@ -148,9 +189,14 @@ oops: int qse_main (int argc, qse_achar_t* argv[]) { + int ret; + #if defined(_WIN32) char locale[100]; - UINT codepage = GetConsoleOutputCP(); + UINT codepage; + WSADATA wsadata; + + codepage = GetConsoleOutputCP(); if (codepage == CP_UTF8) { /*SetConsoleOUtputCP (CP_UTF8);*/ @@ -162,11 +208,38 @@ int qse_main (int argc, qse_achar_t* argv[]) setlocale (LC_ALL, locale); qse_setdflcmgrbyid (QSE_CMGR_SLMB); } + + + if (WSAStartup (MAKEWORD(2,0), &wsadata) != 0) + { + qse_fprintf (QSE_STDERR, QSE_T("Failed to start up winsock\n")); + return -1; + } + #else setlocale (LC_ALL, ""); qse_setdflcmgrbyid (QSE_CMGR_SLMB); #endif - return qse_runmain (argc, argv, httpd_main); +#if defined(HAVE_SSL) + SSL_load_error_strings (); + SSL_library_init (); +#endif + + ret = qse_runmain (argc, argv, httpd_main); + +#if defined(HAVE_SSL) + /*ERR_remove_state ();*/ + ENGINE_cleanup (); + ERR_free_strings (); + EVP_cleanup (); + CRYPTO_cleanup_all_ex_data (); +#endif + +#if defined(_WIN32) + WSACleanup (); +#endif + + return ret; }