From 0f910de1a6e06d436f03e306e3a2cf4867044ca2 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Wed, 29 Mar 2023 01:24:20 +0900 Subject: [PATCH] refactored code in http-txt.c --- lib/hio-http.h | 4 +- lib/http-cgi.c | 6 +- lib/http-fcgi.c | 2 +- lib/http-file.c | 2 +- lib/http-svr.c | 2 +- lib/http-thr.c | 5 +- lib/http-txt.c | 251 +++++++++++++++++++++++++++--------------------- 7 files changed, 152 insertions(+), 120 deletions(-) diff --git a/lib/hio-http.h b/lib/hio-http.h index 95037a2..db67ef5 100644 --- a/lib/hio-http.h +++ b/lib/hio-http.h @@ -555,10 +555,8 @@ HIO_EXPORT int hio_svc_htts_task_endbody ( hio_svc_htts_task_t* task ); - HIO_EXPORT int hio_svc_htts_task_handleexpect100 ( - hio_svc_htts_task_t* task, - int options + hio_svc_htts_task_t* task ); HIO_EXPORT void hio_svc_htts_fmtgmtime ( diff --git a/lib/http-cgi.c b/lib/http-cgi.c index 421a518..97c01d3 100644 --- a/lib/http-cgi.c +++ b/lib/http-cgi.c @@ -535,7 +535,7 @@ static int cgi_client_on_write (hio_dev_sck_t* sck, hio_iolen_t wrlen, void* wrc * i don't need to enable input watching on the peer side */ cgi_mark_over (cgi, CGI_OVER_WRITE_TO_CLIENT); } - else + else if (wrlen > 0) { if (cgi->peer && cgi->task_res_pending_writes == CGI_PENDING_IO_THRESHOLD) { @@ -708,6 +708,8 @@ static int cgi_peer_on_fork (hio_dev_pro_t* pro, void* fork_ctx) return 0; } +/* ----------------------------------------------------------------------- */ + static void bind_task_to_client (cgi_t* cgi, hio_dev_sck_t* csck) { hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(csck); @@ -935,7 +937,7 @@ int hio_svc_htts_docgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r goto oops; /* TODO: must not go to oops. just destroy the cgi and finalize the request .. */ } - if (hio_svc_htts_task_handleexpect100(cgi, options) <= -1) goto oops; + if (hio_svc_htts_task_handleexpect100(cgi) <= -1) goto oops; if (setup_for_content_length(cgi, req) <= -1) goto oops; /* TODO: store current input watching state and use it when destroying the cgi data */ diff --git a/lib/http-fcgi.c b/lib/http-fcgi.c index ffe491f..4426d8d 100644 --- a/lib/http-fcgi.c +++ b/lib/http-fcgi.c @@ -770,7 +770,7 @@ int hio_svc_htts_dofcgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* bind_task_to_client (fcgi, csck); if (bind_task_to_peer(fcgi, fcgis_addr) <= -1) goto oops; - if (hio_svc_htts_task_handleexpect100(fcgi, options) <= -1) goto oops; + if (hio_svc_htts_task_handleexpect100(fcgi) <= -1) goto oops; if (setup_for_content_length(fcgi, req) <= -1) goto oops; /* TODO: store current input watching state and use it when destroying the fcgi data */ diff --git a/lib/http-file.c b/lib/http-file.c index 2b4003d..ce1cba7 100644 --- a/lib/http-file.c +++ b/lib/http-file.c @@ -891,7 +891,7 @@ int hio_svc_htts_dofile (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* bind_task_to_client (file, csck); - if (hio_svc_htts_task_handleexpect100(file, options) <= -1) goto oops; + if (hio_svc_htts_task_handleexpect100(file) <= -1) goto oops; if (setup_for_content_length(file, req) <= -1) goto oops; if (bind_task_to_peer(file, req, actual_file, mime_type) <= -1) goto oops; diff --git a/lib/http-svr.c b/lib/http-svr.c index 316d533..6417e94 100644 --- a/lib/http-svr.c +++ b/lib/http-svr.c @@ -1058,7 +1058,7 @@ int hio_svc_htts_task_sendfinalres (hio_svc_htts_task_t* task, int status_code, return 1; } -int hio_svc_htts_task_handleexpect100 (hio_svc_htts_task_t* task, int options) +int hio_svc_htts_task_handleexpect100 (hio_svc_htts_task_t* task) { #if !defined(TASK_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) if (task->task_req_conlen_unlimited) diff --git a/lib/http-thr.c b/lib/http-thr.c index e38b677..20a0681 100644 --- a/lib/http-thr.c +++ b/lib/http-thr.c @@ -526,13 +526,12 @@ static int thr_client_on_write (hio_dev_sck_t* sck, hio_iolen_t wrlen, void* wrc if (wrlen == 0) { - HIO_DEBUG3 (hio, "HTTS(%p) - indicated EOF to client %p(%d)\n", thr->htts, sck, (int)sck->hnd); /* since EOF has been indicated to the client, it must not write to the client any further. * this also means that i don't need any data from the peer side either. * i don't need to enable input watching on the peer side */ thr_mark_over (thr, THR_OVER_WRITE_TO_CLIENT); } - else + else if (wrlen > 0) { if (thr->peer && thr->task_res_pending_writes == THR_PENDING_IO_THRESHOLD) { @@ -853,7 +852,7 @@ int hio_svc_htts_dothr (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r bind_task_to_client (thr, csck); if (bind_task_to_peer(thr, csck, req, func, ctx) <= -1) goto oops; - if (hio_svc_htts_task_handleexpect100(thr, options) <= -1) goto oops; + if (hio_svc_htts_task_handleexpect100(thr) <= -1) goto oops; if (setup_for_content_length(thr, req) <= -1) goto oops; /* TODO: store current input watching state and use it when destroying the thr data */ diff --git a/lib/http-txt.c b/lib/http-txt.c index d99b67c..ff0c094 100644 --- a/lib/http-txt.c +++ b/lib/http-txt.c @@ -25,6 +25,8 @@ #include #include +#define TXT_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH + #define TXT_OVER_READ_FROM_CLIENT (1 << 0) #define TXT_OVER_WRITE_TO_CLIENT (1 << 1) #define TXT_OVER_ALL (TXT_OVER_READ_FROM_CLIENT | TXT_OVER_WRITE_TO_CLIENT) @@ -36,11 +38,8 @@ struct txt_t hio_svc_htts_task_on_kill_t on_kill; /* user-provided on_kill callback */ int options; - hio_oow_t num_pending_writes_to_client; unsigned int over: 2; /* must be large enough to accomodate TXT_OVER_ALL */ - unsigned int client_eof_detected: 1; - unsigned int client_disconnected: 1; unsigned int client_htrd_recbs_changed: 1; hio_dev_sck_on_read_t client_org_on_read; @@ -50,31 +49,14 @@ struct txt_t }; typedef struct txt_t txt_t; +static void unbind_task_from_client (txt_t* txt, int rcdown); + static void txt_halt_participating_devices (txt_t* txt) { HIO_DEBUG3 (txt->htts->hio, "HTTS(%p) - Halting participating devices in txt state %p(client=%p)\n", txt->htts, txt, txt->task_csck); if (txt->task_csck) hio_dev_sck_halt (txt->task_csck); } -static int txt_write_to_client (txt_t* txt, const void* data, hio_iolen_t dlen) -{ - if (txt->task_csck) - { - txt->num_pending_writes_to_client++; - if (hio_dev_sck_write(txt->task_csck, data, dlen, HIO_NULL, HIO_NULL) <= -1) - { - txt->num_pending_writes_to_client--; - return -1; - } - } - return 0; -} - -static int txt_send_final_status_to_client (txt_t* txt, int status_code, const hio_bch_t* content_type, const hio_bch_t* content_text, int force_close) -{ - return hio_svc_htts_task_sendfinalres(txt, status_code, content_type, content_text, force_close); -} - static HIO_INLINE void txt_mark_over (txt_t* txt, int over_bits) { unsigned int old_over; @@ -96,14 +78,10 @@ static HIO_INLINE void txt_mark_over (txt_t* txt, int over_bits) if (old_over != TXT_OVER_ALL && txt->over == TXT_OVER_ALL) { /* ready to stop */ - if (txt->task_keep_client_alive && !txt->client_eof_detected) + if (txt->task_keep_client_alive) { - /* how to arrange to delete this txt object and put the socket back to the normal waiting state??? */ HIO_ASSERT (txt->htts->hio, txt->task_client->task == (hio_svc_htts_task_t*)txt); - -/*printf ("DETACHING FROM THE MAIN CLIENT TASK... state -> %p\n", txt->task_client->task);*/ - HIO_SVC_HTTS_TASK_UNREF (txt->task_client->task); - /* txt must not be access from here down as it could have been destroyed */ + unbind_task_from_client (txt, 1); } else { @@ -126,28 +104,9 @@ static void txt_on_kill (hio_svc_htts_task_t* task) if (txt->task_csck) { HIO_ASSERT (hio, txt->task_client != HIO_NULL); - - if (txt->client_org_on_read) txt->task_csck->on_read = txt->client_org_on_read; - if (txt->client_org_on_write) txt->task_csck->on_write = txt->client_org_on_write; - if (txt->client_org_on_disconnect) txt->task_csck->on_disconnect = txt->client_org_on_disconnect; - if (txt->client_htrd_recbs_changed) - hio_htrd_setrecbs (txt->task_client->htrd, &txt->client_htrd_org_recbs); - - if (!txt->client_disconnected) - { - if (!txt->task_keep_client_alive || hio_dev_sck_read(txt->task_csck, 1) <= -1) - { - HIO_DEBUG2 (hio, "HTTS(%p) - halting client(%p) for failure to enable input watching\n", txt->htts, txt->task_csck); - hio_dev_sck_halt (txt->task_csck); - } - } + unbind_task_from_client (txt, 0); } - txt->client_org_on_read = HIO_NULL; - txt->client_org_on_write = HIO_NULL; - txt->client_org_on_disconnect = HIO_NULL; - txt->client_htrd_recbs_changed = 0; - if (txt->task_next) HIO_SVC_HTTS_TASKL_UNLINK_TASK (txt); /* detach from the htts service only if it's attached */ } @@ -182,8 +141,19 @@ static void txt_client_on_disconnect (hio_dev_sck_t* sck) { hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(sck); txt_t* txt = (txt_t*)cli->task; - txt->client_disconnected = 1; - txt->client_org_on_disconnect (sck); + + if (txt) + { + HIO_SVC_HTTS_TASK_RCUP (txt); + + unbind_task_from_client (txt, 1); + + /* call the parent handler*/ + /*if (txt->client_org_on_disconnect) txt->client_org_on_disconnect (sck);*/ + if (sck->on_disconnect) sck->on_disconnect (sck); /* restored to the orginal parent handler in unbind_task_from_client() */ + + HIO_SVC_HTTS_TASK_RCDOWN (txt); + } } static int txt_client_on_read (hio_dev_sck_t* sck, const void* buf, hio_iolen_t len, const hio_skad_t* srcaddr) @@ -191,9 +161,12 @@ static int txt_client_on_read (hio_dev_sck_t* sck, const void* buf, hio_iolen_t hio_t* hio = sck->hio; hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(sck); txt_t* txt = (txt_t*)cli->task; + int n; HIO_ASSERT (hio, sck == cli->sck); + n = txt->client_org_on_read? txt->client_org_on_read(sck, buf, len, srcaddr): 0; + if (len <= -1) { /* read error */ @@ -205,28 +178,14 @@ static int txt_client_on_read (hio_dev_sck_t* sck, const void* buf, hio_iolen_t { /* EOF on the client side. arrange to close */ HIO_DEBUG3 (hio, "HTTPS(%p) - EOF from client %p(hnd=%d)\n", txt->htts, sck, (int)sck->hnd); - txt->client_eof_detected = 1; if (!(txt->over & TXT_OVER_READ_FROM_CLIENT)) /* if this is true, EOF is received without txt_client_htrd_poke() */ { txt_mark_over (txt, TXT_OVER_READ_FROM_CLIENT); } } - else - { - hio_oow_t rem; - - HIO_ASSERT (hio, !(txt->over & TXT_OVER_READ_FROM_CLIENT)); - - if (hio_htrd_feed(cli->htrd, buf, len, &rem) <= -1) goto oops; - - if (rem > 0) - { - /* TODO store this to client buffer. once the current resource is completed, arrange to call on_read() with it */ -/*printf ("UUUUUUUUUUUUUUUUUUUUUUUUUUGGGGGHHHHHHHHHHHH .......... TXT CLIENT GIVING EXCESSIVE DATA AFTER CONTENTS...\n");*/ - } - } + if (n <= -1) goto oops; return 0; oops: @@ -239,41 +198,136 @@ static int txt_client_on_write (hio_dev_sck_t* sck, hio_iolen_t wrlen, void* wrc hio_t* hio = sck->hio; hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(sck); txt_t* txt = (txt_t*)cli->task; + int n; - if (wrlen <= -1) - { - HIO_DEBUG3 (hio, "HTTPS(%p) - unable to write to client %p(%d)\n", sck->hio, sck, (int)sck->hnd); - goto oops; - } + n = txt->client_org_on_write? txt->client_org_on_write(sck, wrlen, wrctx, dstaddr): 0; if (wrlen == 0) { - /* if the connect is keep-alive, this part may not be called */ - txt->num_pending_writes_to_client--; - HIO_ASSERT (hio, txt->num_pending_writes_to_client == 0); - HIO_DEBUG3 (hio, "HTTS(%p) - indicated EOF to client %p(%d)\n", txt->htts, sck, (int)sck->hnd); /* since EOF has been indicated to the client, it must not write to the client any further. * this also means that i don't need any data from the peer side either. * i don't need to enable input watching on the peer side */ txt_mark_over (txt, TXT_OVER_WRITE_TO_CLIENT); } + else if (wrlen > 0) + { + if (txt->task_res_pending_writes <= 0) + txt_mark_over (txt, TXT_OVER_WRITE_TO_CLIENT); + } + + if (n <= -1 || wrlen <= -1) txt_halt_participating_devices (txt); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static void bind_task_to_client (txt_t* txt, hio_dev_sck_t* csck) +{ + hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(csck); + + HIO_ASSERT (txt->htts->hio, cli->sck == csck); + HIO_ASSERT (txt->htts->hio, cli->task == HIO_NULL); + + /* txt->task_client and txt->task_csck are set in hio_svc_htts_task_make() */ + + /* remember the client socket's io event handlers */ + txt->client_org_on_read = csck->on_read; + txt->client_org_on_write = csck->on_write; + txt->client_org_on_disconnect = csck->on_disconnect; + + /* set new io events handlers on the client socket */ + csck->on_read = txt_client_on_read; + csck->on_write = txt_client_on_write; + csck->on_disconnect = txt_client_on_disconnect; + + cli->task = (hio_svc_htts_task_t*)txt; + HIO_SVC_HTTS_TASK_RCUP (txt); +} + +static void unbind_task_from_client (txt_t* txt, int rcdown) +{ + hio_dev_sck_t* csck = txt->task_csck; + + HIO_ASSERT (txt->htts->hio, txt->task_client != HIO_NULL); + HIO_ASSERT (txt->htts->hio, txt->task_csck != HIO_NULL); + HIO_ASSERT (txt->htts->hio, txt->task_client->task == (hio_svc_htts_task_t*)txt); + HIO_ASSERT (txt->htts->hio, txt->task_client->htrd != HIO_NULL); + + if (txt->client_htrd_recbs_changed) + { + hio_htrd_setrecbs (txt->task_client->htrd, &txt->client_htrd_org_recbs); + txt->client_htrd_recbs_changed = 0; + } + + if (txt->client_org_on_read) + { + csck->on_read = txt->client_org_on_read; + txt->client_org_on_read = HIO_NULL; + } + + if (txt->client_org_on_write) + { + csck->on_write = txt->client_org_on_write; + txt->client_org_on_write = HIO_NULL; + } + + if (txt->client_org_on_disconnect) + { + csck->on_disconnect = txt->client_org_on_disconnect; + txt->client_org_on_disconnect = HIO_NULL; + } + + /* there is some ordering issue in using HIO_SVC_HTTS_TASK_UNREF() + * because it can destroy the txt itself. so reset txt->task_client->task + * to null and call RCDOWN() later */ + txt->task_client->task = HIO_NULL; + + /* these two lines are also done in csck_on_disconnect() in http-svr.c because the socket is destroyed. + * the same lines here are because the task is unbound while the socket is still alive */ + txt->task_client = HIO_NULL; + txt->task_csck = HIO_NULL; + + /* enable input watching on the socket being unbound */ + if (txt->task_keep_client_alive && hio_dev_sck_read(csck, 1) <= -1) + { + HIO_DEBUG2 (txt->htts->hio, "HTTS(%p) - halting client(%p) for failure to enable input watching\n", txt->htts, csck); + hio_dev_sck_halt (csck); + } + + if (rcdown) HIO_SVC_HTTS_TASK_RCDOWN ((hio_svc_htts_task_t*)txt); +} + +/* ----------------------------------------------------------------------- */ + +static int setup_for_content_length(txt_t* txt, hio_htre_t* req) +{ + int have_content; + +#if defined(TXT_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) + have_content = txt->task_req_conlen > 0 || txt->task_req_conlen_unlimited; +#else + have_content = txt->task_req_conlen > 0; +#endif + + if (txt->task_req_conlen_unlimited) + { + /* change the callbacks to subscribe to contents to be uploaded */ + txt->client_htrd_org_recbs = *hio_htrd_getrecbs(txt->task_client->htrd); + txt_client_htrd_recbs.peek = txt->client_htrd_org_recbs.peek; + hio_htrd_setrecbs (txt->task_client->htrd, &txt_client_htrd_recbs); + txt->client_htrd_recbs_changed = 1; + } else { - HIO_ASSERT (hio, txt->num_pending_writes_to_client > 0); - txt->num_pending_writes_to_client--; - if (txt->num_pending_writes_to_client <= 0) - { - txt_mark_over (txt, TXT_OVER_WRITE_TO_CLIENT); - } + /* no content to be uploaded from the client */ + txt_mark_over (txt, TXT_OVER_READ_FROM_CLIENT); } return 0; - -oops: - txt_halt_participating_devices (txt); - return 0; } +/* ----------------------------------------------------------------------- */ + int hio_svc_htts_dotxt (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* req, int status_code, const hio_bch_t* content_type, const hio_bch_t* content_text, int options, hio_svc_htts_task_on_kill_t on_kill) { hio_t* hio = htts->hio; @@ -290,15 +344,7 @@ int hio_svc_htts_dotxt (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r txt->on_kill = on_kill; txt->options = options; - txt->client_org_on_read = csck->on_read; - txt->client_org_on_write = csck->on_write; - txt->client_org_on_disconnect = csck->on_disconnect; - csck->on_read = txt_client_on_read; - csck->on_write = txt_client_on_write; - csck->on_disconnect = txt_client_on_disconnect; - - HIO_ASSERT (hio, cli->task == HIO_NULL); - HIO_SVC_HTTS_TASK_REF ((hio_svc_htts_task_t*)txt, cli->task); + bind_task_to_client (txt, csck); if (req->flags & HIO_HTRE_ATTR_EXPECT100) { @@ -307,29 +353,16 @@ int hio_svc_htts_dotxt (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* r else if (req->flags & HIO_HTRE_ATTR_EXPECT) { /* 417 Expectation Failed */ - txt_send_final_status_to_client(txt, HIO_HTTP_STATUS_EXPECTATION_FAILED, HIO_NULL, HIO_NULL, 1); + hio_svc_htts_task_sendfinalres(txt, HIO_HTTP_STATUS_EXPECTATION_FAILED, HIO_NULL, HIO_NULL, 1); goto oops; } - if (txt->task_req_conlen_unlimited || txt->task_req_conlen > 0) - { - /* change the callbacks to subscribe to contents to be uploaded */ - txt->client_htrd_org_recbs = *hio_htrd_getrecbs(txt->task_client->htrd); - txt_client_htrd_recbs.peek = txt->client_htrd_org_recbs.peek; - hio_htrd_setrecbs (txt->task_client->htrd, &txt_client_htrd_recbs); - txt->client_htrd_recbs_changed = 1; - } - else - { - /* no content to be uploaded from the client */ - /* indicate EOF to the peer and disable input wathching from the client */ - txt_mark_over (txt, TXT_OVER_READ_FROM_CLIENT); - } + if (setup_for_content_length(txt, req) <= -1) goto oops; /* TODO: store current input watching state and use it when destroying the txt data */ if (hio_dev_sck_read(csck, !(txt->over & TXT_OVER_READ_FROM_CLIENT)) <= -1) goto oops; - if (txt_send_final_status_to_client(txt, status_code, content_type, content_text, 0) <= -1) goto oops; + if (hio_svc_htts_task_sendfinalres(txt, HIO_HTTP_STATUS_OK, content_type, content_text, 0) <= -1) goto oops; HIO_SVC_HTTS_TASKL_APPEND_TASK (&htts->task, (hio_svc_htts_task_t*)txt); return 0;