From e54867e42e86b05675edb43925104f9b68742f86 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sun, 26 Mar 2023 03:01:40 +0900 Subject: [PATCH] touched up http file handler --- lib/hio-http.h | 18 +++ lib/http-cgi.c | 4 +- lib/http-fcgi.c | 2 +- lib/http-file.c | 337 +++++++++++++++++++++--------------------------- lib/http-svr.c | 15 +++ 5 files changed, 184 insertions(+), 192 deletions(-) diff --git a/lib/hio-http.h b/lib/hio-http.h index 853e71d..95037a2 100644 --- a/lib/hio-http.h +++ b/lib/hio-http.h @@ -538,6 +538,24 @@ HIO_EXPORT int hio_svc_htts_task_endreshdr ( hio_svc_htts_task_t* task ); +HIO_EXPORT int hio_svc_htts_task_addresbody ( + hio_svc_htts_task_t* task, + const void* data, + hio_iolen_t dlen +); + +HIO_EXPORT int hio_svc_htts_task_addresbodyfromfile ( + hio_svc_htts_task_t* task, + int fd, + hio_foff_t foff, + hio_iolen_t len +); + +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 diff --git a/lib/http-cgi.c b/lib/http-cgi.c index 6b2ea23..b5fd12d 100644 --- a/lib/http-cgi.c +++ b/lib/http-cgi.c @@ -98,7 +98,6 @@ static int cgi_write_to_peer (cgi_t* cgi, const void* data, hio_iolen_t dlen) return -1; } - /* TODO: check if it's already finished or something.. */ if (cgi->peer_pending_writes > CGI_PENDING_IO_THRESHOLD) { /* suspend input watching */ @@ -159,7 +158,7 @@ static HIO_INLINE void cgi_mark_over (cgi_t* cgi, int over_bits) } else { - HIO_DEBUG5 (hio, "HTTS(%p) - cgi(t=%p,c=%p[%d],p=%p) - halting client for no keep-alive\n", cgi->htts, cgi, cgi->task_client, (cgi->task_csck? cgi->task_csck->hnd: -1), cgi->peer); + HIO_DEBUG5 (hio, "HTTS(%p) - cgi(t=%p,c=%p[%d],p=%p) - halting client\n", cgi->htts, cgi, cgi->task_client, (cgi->task_csck? cgi->task_csck->hnd: -1), cgi->peer); hio_dev_sck_shutdown (cgi->task_csck, HIO_DEV_SCK_SHUTDOWN_WRITE); hio_dev_sck_halt (cgi->task_csck); } @@ -800,6 +799,7 @@ static void unbind_task_from_client (cgi_t* cgi, int rcdown) if (rcdown) HIO_SVC_HTTS_TASK_RCDOWN ((hio_svc_htts_task_t*)cgi); } + /* ----------------------------------------------------------------------- */ static int bind_task_to_peer (cgi_t* cgi, hio_dev_sck_t* csck, hio_htre_t* req, const hio_bch_t* docroot, const hio_bch_t* script) diff --git a/lib/http-fcgi.c b/lib/http-fcgi.c index ba30e57..7dde0ab 100644 --- a/lib/http-fcgi.c +++ b/lib/http-fcgi.c @@ -126,7 +126,7 @@ static HIO_INLINE void fcgi_mark_over (fcgi_t* fcgi, int over_bits) } else { - HIO_DEBUG2 (hio, "HTTS(%p) - halting client(%p) for no keep-alive\n", fcgi->htts, fcgi->task_csck); + HIO_DEBUG2 (hio, "HTTS(%p) - halting client(%p)\n", fcgi->htts, fcgi->task_csck); hio_dev_sck_shutdown (fcgi->task_csck, HIO_DEV_SCK_SHUTDOWN_WRITE); hio_dev_sck_halt (fcgi->task_csck); } diff --git a/lib/http-file.c b/lib/http-file.c index 9b0588c..4656899 100644 --- a/lib/http-file.c +++ b/lib/http-file.c @@ -36,13 +36,6 @@ #define FILE_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH -enum file_res_mode_t -{ - FILE_RES_MODE_CLOSE, - FILE_RES_MODE_LENGTH -}; -typedef enum file_res_mode_t file_res_mode_t; - #define FILE_OVER_READ_FROM_CLIENT (1 << 0) #define FILE_OVER_READ_FROM_PEER (1 << 1) #define FILE_OVER_WRITE_TO_CLIENT (1 << 2) @@ -57,7 +50,7 @@ struct file_t int options; hio_svc_htts_file_cbs_t* cbs; - hio_oow_t num_pending_writes_to_client; + hio_oow_t num_pending_writes_to_peer; int sendfile_ok; int peer; @@ -70,12 +63,8 @@ struct file_t hio_bch_t peer_etag[128]; unsigned int over: 4; /* must be large enough to accomodate FILE_OVER_ALL */ - unsigned int ever_attempted_to_write_to_client: 1; - unsigned int client_eof_detected: 1; - unsigned int client_disconnected: 1; unsigned int client_htrd_recbs_changed: 1; unsigned int etag_match: 1; - file_res_mode_t res_mode_to_cli; hio_dev_sck_on_read_t client_org_on_read; hio_dev_sck_on_write_t client_org_on_write; @@ -84,8 +73,20 @@ struct file_t }; typedef struct file_t file_t; +static void unbind_task_from_client (file_t* file, int rcdown); static int file_send_contents_to_client (file_t* file); +static HIO_INLINE void set_tcp_cork (hio_dev_sck_t* sck, int tcp_cork) +{ +#if defined(TCP_CORK) + #if defined(SOL_TCP) + hio_dev_sck_setsockopt (sck, SOL_TCP, TCP_CORK, &tcp_cork, HIO_SIZEOF(tcp_cork)); + #elif defined(IPPROTO_TCP) + hio_dev_sck_setsockopt (sck, IPPROTO_TCP, TCP_CORK, &tcp_cork, HIO_SIZEOF(tcp_cork)); + #endif +#endif +} + static void file_halt_participating_devices (file_t* file) { HIO_DEBUG3 (file->htts->hio, "HTTS(%p) - file(c=%d,p=%d) Halting participating devices\n", file->htts, (int)file->task_csck->hnd, (int)file->peer); @@ -95,45 +96,6 @@ static void file_halt_participating_devices (file_t* file) if (file->task_csck) hio_dev_sck_halt (file->task_csck); } -static int file_write_to_client (file_t* file, const void* data, hio_iolen_t dlen) -{ - if (file->task_csck) - { - file->ever_attempted_to_write_to_client = 1; - - file->num_pending_writes_to_client++; - if (hio_dev_sck_write(file->task_csck, data, dlen, HIO_NULL, HIO_NULL) <= -1) /* TODO: use sendfile here.. */ - { - file->num_pending_writes_to_client--; - return -1; - } - } - - return 0; -} - -static int file_sendfile_to_client (file_t* file, hio_foff_t foff, hio_iolen_t len) -{ - if (file->task_csck) - { - file->ever_attempted_to_write_to_client = 1; - - file->num_pending_writes_to_client++; - if (hio_dev_sck_sendfile(file->task_csck, file->peer, foff, len, HIO_NULL) <= -1) - { - file->num_pending_writes_to_client--; - return -1; - } - } - - return 0; -} - -static int file_send_final_status_to_client (file_t* file, int status_code, int force_close) -{ - return hio_svc_htts_task_sendfinalres(file, status_code, HIO_NULL, HIO_NULL, force_close); -} - static void file_close_peer (file_t* file) { hio_t* hio = file->htts->hio; @@ -153,18 +115,20 @@ static void file_close_peer (file_t* file) static void file_mark_over (file_t* file, int over_bits) { + hio_svc_htts_t* htts = file->htts; + hio_t* hio = htts->hio; unsigned int old_over; old_over = file->over; file->over |= over_bits; - HIO_DEBUG6 (file->htts->hio, "HTTS(%p) - file(c=%d,p=%d) updating mark - old_over=%x | new-bits=%x => over=%x\n", file->htts, (int)file->task_csck->hnd, file->peer, (int)old_over, (int)over_bits, (int)file->over); + HIO_DEBUG6 (hio, "HTTS(%p) - file(c=%d,p=%d) updating mark - old_over=%x | new-bits=%x => over=%x\n", htts, (int)file->task_csck->hnd, file->peer, (int)old_over, (int)over_bits, (int)file->over); if (!(old_over & FILE_OVER_READ_FROM_CLIENT) && (file->over & FILE_OVER_READ_FROM_CLIENT)) { if (file->task_csck && hio_dev_sck_read(file->task_csck, 0) <= -1) { - HIO_DEBUG3 (file->htts->hio, "HTTS(%p) - file(c=%d,p=%d) halting client for failure to disable input watching\n", file->htts, (int)file->task_csck->hnd, file->peer); + HIO_DEBUG3 (hio, "HTTS(%p) - file(c=%d,p=%d) halting client for failure to disable input watching\n", htts, (int)file->task_csck->hnd, file->peer); hio_dev_sck_halt (file->task_csck); } } @@ -179,30 +143,23 @@ static void file_mark_over (file_t* file, int over_bits) if (old_over != FILE_OVER_ALL && file->over == FILE_OVER_ALL) { /* ready to stop */ - HIO_DEBUG3 (file->htts->hio, "HTTS(%p) - file(c=%d,p=%d) halting peer as it is unneeded\n", file->htts, (int)file->task_csck->hnd, file->peer); + HIO_DEBUG3 (hio, "HTTS(%p) - file(c=%d,p=%d) halting peer as it is unneeded\n", htts, (int)file->task_csck->hnd, file->peer); file_close_peer (file); - if (HIO_LIKELY(file->task_csck)) + if (file->task_csck) { - if (file->task_keep_client_alive && !file->client_eof_detected) + if (file->task_keep_client_alive) { - #if defined(TCP_CORK) - int tcp_cork = 0; - #if defined(SOL_TCP) - hio_dev_sck_setsockopt(file->task_csck, SOL_TCP, TCP_CORK, &tcp_cork, HIO_SIZEOF(tcp_cork)); - #elif defined(IPPROTO_TCP) - hio_dev_sck_setsockopt(file->task_csck, IPPROTO_TCP, TCP_CORK, &tcp_cork, HIO_SIZEOF(tcp_cork)); - #endif - #endif + set_tcp_cork (file->task_csck, 0); - /* how to arrange to delete this file object and put the socket back to the normal waiting state??? */ - HIO_ASSERT (file->htts->hio, file->task_client->task == (hio_svc_htts_task_t*)file); - HIO_SVC_HTTS_TASK_UNREF (file->task_client->task); /* the file task must not be accessed from here down as it could have been destroyed */ + HIO_DEBUG2 (hio, "HTTS(%p) - keeping client(%p) alive\n", htts, file->task_csck); + HIO_ASSERT (hio, file->task_client->task == (hio_svc_htts_task_t*)file); + unbind_task_from_client (file, 1); } else { - HIO_DEBUG4 (file->htts->hio, "HTTS(%p) - file(c=%d,p=%d) halting client for %hs\n", file->htts, (int)file->task_csck->hnd, file->peer, (file->client_eof_detected? "EOF detected": "no keep-alive")); + HIO_DEBUG2 (hio, "HTTS(%p) - halting client(%p)\n", htts, file->task_csck); hio_dev_sck_shutdown (file->task_csck, HIO_DEV_SCK_SHUTDOWN_WRITE); hio_dev_sck_halt (file->task_csck); /* the file task will be detached from file->task_client->task by the upstream disconnect handler in http_svr.c */ @@ -253,24 +210,12 @@ static void file_on_kill (hio_svc_htts_task_t* task) if (file->task_csck) { - if (file->client_org_on_read) file->task_csck->on_read = file->client_org_on_read; - if (file->client_org_on_write) file->task_csck->on_write = file->client_org_on_write; - if (file->client_org_on_disconnect) file->task_csck->on_disconnect = file->client_org_on_disconnect; - if (file->client_htrd_recbs_changed) hio_htrd_setrecbs (file->task_client->htrd, &file->client_htrd_org_recbs); - - if (!file->task_keep_client_alive || hio_dev_sck_read(file->task_csck, 1) <= -1) - { - HIO_DEBUG5 (hio, "HTTS(%p) - file(t=%p,c=%p[%d],p=%d) - halting client for failure to enable input watching\n", file->htts, file, file->task_client, (file->task_csck? file->task_csck->hnd: -1), file->peer); - hio_dev_sck_halt (file->task_csck); - } + HIO_ASSERT (hio, file->task_client != HIO_NULL); + unbind_task_from_client (file, 0); } - file->client_org_on_read = HIO_NULL; - file->client_org_on_write = HIO_NULL; - file->client_org_on_disconnect = HIO_NULL; - file->client_htrd_recbs_changed = 0; - if (file->task_next) HIO_SVC_HTTS_TASKL_UNLINK_TASK (file); /* detach from the htts service only if it's attached */ + HIO_DEBUG5 (hio, "HTTS(%p) - file(t=%p,c=%p[%d],p=%d) - killed the task\n", file->htts, file, file->task_client, (file->task_csck? file->task_csck->hnd: -1), file->peer); } @@ -286,14 +231,18 @@ static void file_client_on_disconnect (hio_dev_sck_t* sck) HIO_DEBUG4 (hio, "HTTS(%p) - file(t=%p,c=%p,csck=%p) - client socket disconnect notified\n", htts, file, sck, cli); - file->client_disconnected = 1; - file->task_csck = HIO_NULL; - file->task_client = HIO_NULL; - if (file->client_org_on_disconnect) + if (file) { - file->client_org_on_disconnect (sck); - /* this original callback(listener_on_disconnect in http-svr.c) destroys the associated resource. - * the `file` task object must not be accessed from here down */ + HIO_SVC_HTTS_TASK_RCUP (file); + + /* detach the task from the client and the client socket */ + unbind_task_from_client (file, 1); + + /* call the parent handler*/ + /*if (file->client_org_on_disconnect) file->client_org_on_disconnect (sck);*/ + if (sck->on_disconnect) sck->on_disconnect (sck); /* restored to the orginal parent handelr in unbind_task_from_client() */ + + HIO_SVC_HTTS_TASK_RCDOWN (file); } HIO_DEBUG4 (hio, "HTTS(%p) - file(t=%p,c=%p,csck=%p) - client socket disconnect handled\n", htts, file, sck, cli); @@ -327,7 +276,7 @@ static int file_client_on_read (hio_dev_sck_t* sck, const void* buf, hio_iolen_t { /* EOF on the client side. arrange to close */ HIO_DEBUG3 (cli->htts->hio, "HTTS(%p) - file(c=%d,p=%d) EOF detected on client\n", file->htts, (int)sck->hnd, file->peer); - file->client_eof_detected = 1; + //file->client_eof_detected = 1; if (!(file->over & FILE_OVER_READ_FROM_CLIENT)) /* if this is true, EOF is received without file_client_htrd_poke() */ { @@ -364,42 +313,26 @@ static int file_client_on_write (hio_dev_sck_t* sck, hio_iolen_t wrlen, void* wr hio_t* hio = sck->hio; hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(sck); file_t* file = (file_t*)cli->task; + int n; - HIO_ASSERT (hio, sck == cli->sck); - HIO_ASSERT (hio, sck == file->task_csck); - - if (wrlen <= -1) - { - HIO_DEBUG3 (hio, "HTTS(%p) - file(c=%d,p=%d) unable to write to client\n", file->htts, (int)sck->hnd, file->peer); - goto oops; - } + n = file->client_org_on_write? file->client_org_on_write(sck, wrlen, wrctx, dstaddr): 0; if (wrlen == 0) { - /* if the connect is keep-alive, this part may not be called */ - file->num_pending_writes_to_client--; - HIO_ASSERT (hio, file->num_pending_writes_to_client == 0); - HIO_DEBUG3 (hio, "HTTS(%p) - file(c=%d,p=%d) indicated EOF to client\n", file->htts, (int)sck->hnd, file->peer); - /* 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 */ - file_mark_over (file, FILE_OVER_WRITE_TO_CLIENT); } - else + else if (wrlen > 0) { - HIO_ASSERT (hio, file->num_pending_writes_to_client > 0); - file->num_pending_writes_to_client--; - if (file->task_req_method == HIO_HTTP_GET) file_send_contents_to_client (file); - if ((file->over & FILE_OVER_READ_FROM_PEER) && file->num_pending_writes_to_client <= 0) + if ((file->over & FILE_OVER_READ_FROM_PEER) && file->task_res_pending_writes <= 0) { file_mark_over (file, FILE_OVER_WRITE_TO_CLIENT); } } + if (n <= -1 || wrlen <= -1) file_halt_participating_devices (file); return 0; oops: @@ -422,7 +355,7 @@ static int file_client_htrd_poke (hio_htrd_t* htrd, hio_htre_t* req) if (file->task_req_method != HIO_HTTP_GET) { - if (file_send_final_status_to_client(file, HIO_HTTP_STATUS_OK, 0) <= -1) return -1; + if (hio_svc_htts_task_sendfinalres(file, HIO_HTTP_STATUS_OK, HIO_NULL, HIO_NULL, 0) <= -1) return -1; } file_mark_over (file, FILE_OVER_READ_FROM_CLIENT); @@ -465,7 +398,6 @@ static int file_send_header_to_client (file_t* file, int status_code, int force_ if (hio_svc_htts_task_startreshdr(file, status_code, HIO_NULL, 0) <= -1) return -1; - if (mime_type && mime_type[0] != '\0' && hio_svc_htts_task_addreshdr(file, "Content-Type", mime_type) <= -1) return -1; if ((file->task_req_method == HIO_HTTP_GET || file->task_req_method == HIO_HTTP_HEAD) && @@ -490,10 +422,7 @@ static int file_send_header_to_client (file_t* file, int status_code, int force_ static void send_contents_to_client_later (hio_t* hio, const hio_ntime_t* now, hio_tmrjob_t* tmrjob) { file_t* file = (file_t*)tmrjob->ctx; - if (file_send_contents_to_client(file) <= -1) - { - file_halt_participating_devices (file); - } + if (file_send_contents_to_client(file) <= -1) file_halt_participating_devices (file); } static int file_send_contents_to_client (file_t* file) @@ -512,7 +441,7 @@ static int file_send_contents_to_client (file_t* file) if (file->sendfile_ok) { if (lim > 0x7FFF0000) lim = 0x7FFF0000; /* TODO: change this... */ - if (file_sendfile_to_client(file, file->cur_offset, lim) <= -1) return -1; + if (hio_svc_htts_task_addresbodyfromfile(file, file->peer, file->cur_offset, lim) <= -1) return -1; file->cur_offset += lim; } else @@ -544,7 +473,8 @@ static int file_send_contents_to_client (file_t* file) return -1; } - if (file_write_to_client(file, file->peer_buf, n) <= -1) return -1; + //if (file_write_to_client(file, file->peer_buf, n) <= -1) return -1; + if (hio_svc_htts_task_addresbody(file, file->peer_buf, n) <= -1) return -1; file->cur_offset += n; @@ -709,89 +639,85 @@ static int open_peer_with_mode (file_t* file, const hio_bch_t* actual_file, int return 0; } -static HIO_INLINE void set_tcp_cork (hio_dev_sck_t* sck) +static void bind_task_to_client (file_t* file, hio_dev_sck_t* csck) { -#if defined(TCP_CORK) - int tcp_cork = 1; - #if defined(SOL_TCP) - hio_dev_sck_setsockopt (sck, SOL_TCP, TCP_CORK, &tcp_cork, HIO_SIZEOF(tcp_cork)); - #elif defined(IPPROTO_TCP) - hio_dev_sck_setsockopt (sck, IPPROTO_TCP, TCP_CORK, &tcp_cork, HIO_SIZEOF(tcp_cork)); - #endif -#endif -} - -int hio_svc_htts_dofile (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* req, const hio_bch_t* docroot, const hio_bch_t* filepath, const hio_bch_t* mime_type, int options, hio_svc_htts_task_on_kill_t on_kill, hio_svc_htts_file_cbs_t* cbs) -{ - hio_t* hio = htts->hio; hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(csck); - file_t* file = HIO_NULL; - hio_bch_t* actual_file = HIO_NULL; - int status_code; - /* ensure that you call this function before any contents is received */ - HIO_ASSERT (hio, hio_htre_getcontentlen(req) == 0); - HIO_ASSERT (hio, cli->sck == csck); + HIO_ASSERT (file->htts->hio, cli->sck == csck); + HIO_ASSERT (file->htts->hio, cli->task == HIO_NULL); - HIO_DEBUG5 (hio, "HTTS(%p) - file(c=%d) - [%hs] %hs%hs\n", htts, (int)csck->hnd, cli->cli_addr_bcstr, (docroot[0] == '/' && docroot[1] == '\0' && filepath[0] == '/'? "": docroot), filepath); - - actual_file = hio_svc_htts_dupmergepaths(htts, docroot, filepath); - if (HIO_UNLIKELY(!actual_file)) goto oops; - - file = (file_t*)hio_svc_htts_task_make(htts, HIO_SIZEOF(*file), file_on_kill, req, csck); - if (HIO_UNLIKELY(!file)) goto oops; - - file->on_kill = on_kill; - file->options = options; - file->cbs = cbs; /* the given pointer must outlive the lifespan of the while file handling cycle. */ - file->sendfile_ok = hio_dev_sck_sendfileok(csck); + /* file->task_client and file->task_csck are set in hio_svc_htts_task_make() */ + /* remember the client socket's io event handlers */ file->client_org_on_read = csck->on_read; file->client_org_on_write = csck->on_write; file->client_org_on_disconnect = csck->on_disconnect; + + /* set new io events handlers on the client socket */ csck->on_read = file_client_on_read; csck->on_write = file_client_on_write; csck->on_disconnect = file_client_on_disconnect; - file->peer_tmridx = HIO_TMRIDX_INVALID; - file->peer = -1; + cli->task = (hio_svc_htts_task_t*)file; + HIO_SVC_HTTS_TASK_RCUP (file); +} - HIO_ASSERT (hio, cli->task == HIO_NULL); /* you must not call this function while cli->task is not HIO_NULL */ - HIO_SVC_HTTS_TASK_REF ((hio_svc_htts_task_t*)file, cli->task); /* cli->task = file with ref-count up */ +static void unbind_task_from_client (file_t* file, int rcdown) +{ + hio_dev_sck_t* csck = file->task_csck; -#if !defined(FILE_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) - if (file->task_req_conlen_unlimited) + HIO_ASSERT (file->htts->hio, file->task_client != HIO_NULL); + HIO_ASSERT (file->htts->hio, file->task_csck != HIO_NULL); + HIO_ASSERT (file->htts->hio, file->task_client->task == (hio_svc_htts_task_t*)file); + HIO_ASSERT (file->htts->hio, file->task_client->htrd != HIO_NULL); + + if (file->client_htrd_recbs_changed) { - /* Transfer-Encoding is chunked. no content-length is known in advance. */ - - /* option 1. buffer contents. if it gets too large, send 413 Request Entity Too Large. - * option 2. send 411 Length Required immediately - * option 3. set Content-Length to -1 and use EOF to indicate the end of content [Non-Standard] */ - if (file_send_final_status_to_client(file, HIO_HTTP_STATUS_LENGTH_REQUIRED, 1) <= -1) goto oops; - } -#endif - - if (req->flags & HIO_HTRE_ATTR_EXPECT100) - { - if (hio_comp_http_version_numbers(&req->version, 1, 1) >= 0 && - (file->task_req_conlen_unlimited || file->task_req_conlen > 0) && - (file->task_req_method != HIO_HTTP_GET && file->task_req_method != HIO_HTTP_HEAD)) - { - hio_bch_t msgbuf[64]; - hio_oow_t msglen; - - msglen = hio_fmttobcstr(hio, msgbuf, HIO_COUNTOF(msgbuf), "HTTP/%d.%d %d %hs\r\n\r\n", file->task_req_version.major, file->task_req_version.minor, HIO_HTTP_STATUS_CONTINUE, hio_http_status_to_bcstr(HIO_HTTP_STATUS_CONTINUE)); - if (file_write_to_client(file, msgbuf, msglen) <= -1) goto oops; - file->ever_attempted_to_write_to_client = 0; /* reset this as it's polluted for 100 continue */ - } - } - else if (req->flags & HIO_HTRE_ATTR_EXPECT) - { - /* 417 Expectation Failed */ - file_send_final_status_to_client (file, HIO_HTTP_STATUS_EXPECTATION_FAILED, 1); - goto oops; + hio_htrd_setrecbs (file->task_client->htrd, &file->client_htrd_org_recbs); + file->client_htrd_recbs_changed = 0; } + if (file->client_org_on_read) + { + csck->on_read = file->client_org_on_read; + file->client_org_on_read = HIO_NULL; + } + + if (file->client_org_on_write) + { + csck->on_write = file->client_org_on_write; + file->client_org_on_write = HIO_NULL; + } + + if (file->client_org_on_disconnect) + { + csck->on_disconnect = file->client_org_on_disconnect; + file->client_org_on_disconnect = HIO_NULL; + } + + /* there is some ordering issue in using HIO_SVC_HTTS_TASK_UNREF() + * because it can destroy the file itself. so reset file->task_client->task + * to null and call RCDOWN() later */ + file->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 */ + file->task_client = HIO_NULL; + file->task_csck = HIO_NULL; + + /* enable input watching on the socket being unbound */ + if (file->task_keep_client_alive && hio_dev_sck_read(csck, 1) <= -1) + { + HIO_DEBUG2 (file->htts->hio, "HTTS(%p) - halting client(%p) for failure to enable input watching\n", file->htts, csck); + hio_dev_sck_halt (csck); + } + + if (rcdown) HIO_SVC_HTTS_TASK_RCDOWN ((hio_svc_htts_task_t*)file); +} + + +static int setup_for_content_length(file_t* file, hio_htre_t* req) +{ #if defined(FILE_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) if (file->task_req_conlen_unlimited) { @@ -829,7 +755,40 @@ int hio_svc_htts_dofile (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* } #endif - file->res_mode_to_cli = file->task_keep_client_alive? FILE_RES_MODE_LENGTH: FILE_RES_MODE_CLOSE; + return 0; +} + +int hio_svc_htts_dofile (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* req, const hio_bch_t* docroot, const hio_bch_t* filepath, const hio_bch_t* mime_type, int options, hio_svc_htts_task_on_kill_t on_kill, hio_svc_htts_file_cbs_t* cbs) +{ + hio_t* hio = htts->hio; + hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(csck); + file_t* file = HIO_NULL; + hio_bch_t* actual_file = HIO_NULL; + int status_code; + + /* ensure that you call this function before any contents is received */ + HIO_ASSERT (hio, hio_htre_getcontentlen(req) == 0); + HIO_ASSERT (hio, cli->sck == csck); + + HIO_DEBUG5 (hio, "HTTS(%p) - file(c=%d) - [%hs] %hs%hs\n", htts, (int)csck->hnd, cli->cli_addr_bcstr, (docroot[0] == '/' && docroot[1] == '\0' && filepath[0] == '/'? "": docroot), filepath); + + actual_file = hio_svc_htts_dupmergepaths(htts, docroot, filepath); + if (HIO_UNLIKELY(!actual_file)) goto oops; + + file = (file_t*)hio_svc_htts_task_make(htts, HIO_SIZEOF(*file), file_on_kill, req, csck); + if (HIO_UNLIKELY(!file)) goto oops; + + file->on_kill = on_kill; + file->options = options; + file->cbs = cbs; /* the given pointer must outlive the lifespan of the while file handling cycle. */ + file->sendfile_ok = hio_dev_sck_sendfileok(csck); + + bind_task_to_client (file, csck); + file->peer_tmridx = HIO_TMRIDX_INVALID; + file->peer = -1; + + if (hio_svc_htts_task_handleexpect100(file, options) <= -1) goto oops; + if (setup_for_content_length(file, req) <= -1) goto oops; switch (file->task_req_method) { @@ -853,7 +812,7 @@ int hio_svc_htts_dofile (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* #if defined(HAVE_POSIX_FADVISE) posix_fadvise (file->peer, file->start_offset, file->end_offset - file->start_offset + 1, POSIX_FADV_SEQUENTIAL); #endif - set_tcp_cork (file->task_csck); + set_tcp_cork (file->task_csck, 1); if (file_send_header_to_client(file, HIO_HTTP_STATUS_OK, 0, actual_mime_type) <= -1) goto oops; if (file_send_contents_to_client(file) <= -1) goto oops; @@ -903,7 +862,7 @@ int hio_svc_htts_dofile (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* default: status_code = HIO_HTTP_STATUS_METHOD_NOT_ALLOWED; done_with_status_code: - if (file_send_final_status_to_client(file, status_code, 0) <= -1) goto oops; + if (hio_svc_htts_task_sendfinalres(file, status_code, HIO_NULL, HIO_NULL, 0) <= -1) goto oops; done_with_status_code_2: file_mark_over (file, FILE_OVER_READ_FROM_PEER | FILE_OVER_WRITE_TO_PEER); break; diff --git a/lib/http-svr.c b/lib/http-svr.c index 052d91c..316d533 100644 --- a/lib/http-svr.c +++ b/lib/http-svr.c @@ -961,6 +961,21 @@ int hio_svc_htts_task_addresbody (hio_svc_htts_task_t* task, const void* data, h return task->task_res_chunked? write_chunk_to_client(task, data, dlen): write_raw_to_client(task, data, dlen); } +int hio_svc_htts_task_addresbodyfromfile (hio_svc_htts_task_t* task, int fd, hio_foff_t foff, hio_iolen_t len) +{ + if (task->task_csck) + { + task->task_res_pending_writes++; + if (hio_dev_sck_sendfile(task->task_csck, fd, foff, len, &htts_svr_wrctx) <= -1) + { + task->task_res_pending_writes--; + return -1; + } + } + + return 0; +} + int hio_svc_htts_task_endbody (hio_svc_htts_task_t* task) { /* send the last chunk */