touched up http file handler

This commit is contained in:
hyung-hwan 2023-03-26 03:01:40 +09:00
parent cb15015ffc
commit e54867e42e
5 changed files with 184 additions and 192 deletions

View File

@ -538,6 +538,24 @@ HIO_EXPORT int hio_svc_htts_task_endreshdr (
hio_svc_htts_task_t* task 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_EXPORT int hio_svc_htts_task_handleexpect100 (
hio_svc_htts_task_t* task, hio_svc_htts_task_t* task,
int options int options

View File

@ -98,7 +98,6 @@ static int cgi_write_to_peer (cgi_t* cgi, const void* data, hio_iolen_t dlen)
return -1; return -1;
} }
/* TODO: check if it's already finished or something.. */
if (cgi->peer_pending_writes > CGI_PENDING_IO_THRESHOLD) if (cgi->peer_pending_writes > CGI_PENDING_IO_THRESHOLD)
{ {
/* suspend input watching */ /* suspend input watching */
@ -159,7 +158,7 @@ static HIO_INLINE void cgi_mark_over (cgi_t* cgi, int over_bits)
} }
else 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_shutdown (cgi->task_csck, HIO_DEV_SCK_SHUTDOWN_WRITE);
hio_dev_sck_halt (cgi->task_csck); 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); 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) 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)

View File

@ -126,7 +126,7 @@ static HIO_INLINE void fcgi_mark_over (fcgi_t* fcgi, int over_bits)
} }
else 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_shutdown (fcgi->task_csck, HIO_DEV_SCK_SHUTDOWN_WRITE);
hio_dev_sck_halt (fcgi->task_csck); hio_dev_sck_halt (fcgi->task_csck);
} }

View File

@ -36,13 +36,6 @@
#define FILE_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH #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_CLIENT (1 << 0)
#define FILE_OVER_READ_FROM_PEER (1 << 1) #define FILE_OVER_READ_FROM_PEER (1 << 1)
#define FILE_OVER_WRITE_TO_CLIENT (1 << 2) #define FILE_OVER_WRITE_TO_CLIENT (1 << 2)
@ -57,7 +50,7 @@ struct file_t
int options; int options;
hio_svc_htts_file_cbs_t* cbs; hio_svc_htts_file_cbs_t* cbs;
hio_oow_t num_pending_writes_to_client;
hio_oow_t num_pending_writes_to_peer; hio_oow_t num_pending_writes_to_peer;
int sendfile_ok; int sendfile_ok;
int peer; int peer;
@ -70,12 +63,8 @@ struct file_t
hio_bch_t peer_etag[128]; hio_bch_t peer_etag[128];
unsigned int over: 4; /* must be large enough to accomodate FILE_OVER_ALL */ 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 client_htrd_recbs_changed: 1;
unsigned int etag_match: 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_read_t client_org_on_read;
hio_dev_sck_on_write_t client_org_on_write; hio_dev_sck_on_write_t client_org_on_write;
@ -84,8 +73,20 @@ struct file_t
}; };
typedef struct file_t 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 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) 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); 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); 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) static void file_close_peer (file_t* file)
{ {
hio_t* hio = file->htts->hio; 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) 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; unsigned int old_over;
old_over = file->over; old_over = file->over;
file->over |= over_bits; 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 (!(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) 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); 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) if (old_over != FILE_OVER_ALL && file->over == FILE_OVER_ALL)
{ {
/* ready to stop */ /* 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); 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) set_tcp_cork (file->task_csck, 0);
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
/* 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 */ /* 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 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_shutdown (file->task_csck, HIO_DEV_SCK_SHUTDOWN_WRITE);
hio_dev_sck_halt (file->task_csck); 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 */ /* 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->task_csck)
{ {
if (file->client_org_on_read) file->task_csck->on_read = file->client_org_on_read; HIO_ASSERT (hio, file->task_client != HIO_NULL);
if (file->client_org_on_write) file->task_csck->on_write = file->client_org_on_write; unbind_task_from_client (file, 0);
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);
} }
}
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 */ 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); 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); 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; if (file)
file->task_csck = HIO_NULL;
file->task_client = HIO_NULL;
if (file->client_org_on_disconnect)
{ {
file->client_org_on_disconnect (sck); HIO_SVC_HTTS_TASK_RCUP (file);
/* 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 */ /* 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); 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 */ /* 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); 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() */ 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_t* hio = sck->hio;
hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(sck); hio_svc_htts_cli_t* cli = hio_dev_sck_getxtn(sck);
file_t* file = (file_t*)cli->task; file_t* file = (file_t*)cli->task;
int n;
HIO_ASSERT (hio, sck == cli->sck); n = file->client_org_on_write? file->client_org_on_write(sck, wrlen, wrctx, dstaddr): 0;
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;
}
if (wrlen == 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); 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) if (file->task_req_method == HIO_HTTP_GET)
file_send_contents_to_client (file); 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); file_mark_over (file, FILE_OVER_WRITE_TO_CLIENT);
} }
} }
if (n <= -1 || wrlen <= -1) file_halt_participating_devices (file);
return 0; return 0;
oops: 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->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); 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 (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 (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) && 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) 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; file_t* file = (file_t*)tmrjob->ctx;
if (file_send_contents_to_client(file) <= -1) if (file_send_contents_to_client(file) <= -1) file_halt_participating_devices (file);
{
file_halt_participating_devices (file);
}
} }
static int file_send_contents_to_client (file_t* 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 (file->sendfile_ok)
{ {
if (lim > 0x7FFF0000) lim = 0x7FFF0000; /* TODO: change this... */ 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; file->cur_offset += lim;
} }
else else
@ -544,7 +473,8 @@ static int file_send_contents_to_client (file_t* file)
return -1; 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; 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; 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); 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 (file->htts->hio, cli->sck == csck);
HIO_ASSERT (hio, hio_htre_getcontentlen(req) == 0); HIO_ASSERT (file->htts->hio, cli->task == HIO_NULL);
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); /* file->task_client and file->task_csck are set in hio_svc_htts_task_make() */
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);
/* remember the client socket's io event handlers */
file->client_org_on_read = csck->on_read; file->client_org_on_read = csck->on_read;
file->client_org_on_write = csck->on_write; file->client_org_on_write = csck->on_write;
file->client_org_on_disconnect = csck->on_disconnect; 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_read = file_client_on_read;
csck->on_write = file_client_on_write; csck->on_write = file_client_on_write;
csck->on_disconnect = file_client_on_disconnect; csck->on_disconnect = file_client_on_disconnect;
file->peer_tmridx = HIO_TMRIDX_INVALID; cli->task = (hio_svc_htts_task_t*)file;
file->peer = -1; 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 */
#if !defined(FILE_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH)
if (file->task_req_conlen_unlimited)
{
/* 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;
} }
static void unbind_task_from_client (file_t* file, int rcdown)
{
hio_dev_sck_t* csck = file->task_csck;
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)
{
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 defined(FILE_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH)
if (file->task_req_conlen_unlimited) 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 #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) 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) #if defined(HAVE_POSIX_FADVISE)
posix_fadvise (file->peer, file->start_offset, file->end_offset - file->start_offset + 1, POSIX_FADV_SEQUENTIAL); posix_fadvise (file->peer, file->start_offset, file->end_offset - file->start_offset + 1, POSIX_FADV_SEQUENTIAL);
#endif #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_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; 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: default:
status_code = HIO_HTTP_STATUS_METHOD_NOT_ALLOWED; status_code = HIO_HTTP_STATUS_METHOD_NOT_ALLOWED;
done_with_status_code: 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: done_with_status_code_2:
file_mark_over (file, FILE_OVER_READ_FROM_PEER | FILE_OVER_WRITE_TO_PEER); file_mark_over (file, FILE_OVER_READ_FROM_PEER | FILE_OVER_WRITE_TO_PEER);
break; break;

View File

@ -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); 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) int hio_svc_htts_task_endbody (hio_svc_htts_task_t* task)
{ {
/* send the last chunk */ /* send the last chunk */