From fc26f4a6c3cabf2a3858fa23bc725b2831ca2a84 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Tue, 19 May 2020 09:11:39 +0000 Subject: [PATCH] still working on cgi handling in http server --- mio/bin/t01.c | 2 +- mio/lib/http-svr.c | 273 +++++++++++++++++++++++++++++---------------- mio/lib/mio-sck.h | 15 ++- mio/lib/mio.c | 4 +- mio/lib/pro.c | 36 +++++- mio/lib/sck.c | 27 ++++- mio/t/t1.txt | 13 +++ mio/t/t2.txt | 15 +++ mio/t/t3.txt | 13 +++ 9 files changed, 294 insertions(+), 104 deletions(-) create mode 100644 mio/t/t1.txt create mode 100644 mio/t/t2.txt create mode 100644 mio/t/t3.txt diff --git a/mio/bin/t01.c b/mio/bin/t01.c index d67ffef..75433c6 100644 --- a/mio/bin/t01.c +++ b/mio/bin/t01.c @@ -472,7 +472,7 @@ static void send_icmp (mio_dev_sck_t* dev, mio_uint16_t seq) icmphdr->u.echo.seq = mio_hton16(seq); memset (&buf[MIO_SIZEOF(*icmphdr)], 'A', MIO_SIZEOF(buf) - MIO_SIZEOF(*icmphdr)); - icmphdr->checksum = mio_checksumip (icmphdr, MIO_SIZEOF(buf)); + icmphdr->checksum = mio_checksum_ip(icmphdr, MIO_SIZEOF(buf)); if (mio_dev_sck_write(dev, buf, MIO_SIZEOF(buf), MIO_NULL, &dstaddr) <= -1) { diff --git a/mio/lib/http-svr.c b/mio/lib/http-svr.c index add7d7d..f5bc6ac 100644 --- a/mio/lib/http-svr.c +++ b/mio/lib/http-svr.c @@ -254,6 +254,10 @@ static int init_client (mio_svc_htts_cli_t* cli, mio_dev_sck_t* sck) cli->htrd = mio_htrd_open(sck->mio, MIO_SIZEOF(*htrdxtn)); if (MIO_UNLIKELY(!cli->htrd)) goto oops; + /* With MIO_HTRD_TRAILERS, htrd stores trailers in a separate place. + * Otherwise, it is merged to the headers. */ + /*mio_htrd_setopt (cli->htrd, MIO_HTRD_REQUEST | MIO_HTRD_TRAILERS);*/ + cli->sbuf = mio_becs_open(sck->mio, 0, 2048); if (MIO_UNLIKELY(!cli->sbuf)) goto oops; @@ -616,6 +620,13 @@ typedef enum cgi_state_res_mode_t cgi_state_res_mode_t; #define CGI_STATE_PENDING_IO_THRESHOLD 5 +#define CGI_STATE_OVER_READ_FROM_CLIENT (1 << 0) +#define CGI_STATE_OVER_READ_FROM_PEER (1 << 1) +#define CGI_STATE_OVER_WRITE_TO_CLIENT (1 << 2) +#define CGI_STATE_OVER_WRITE_TO_PEER (1 << 3) +#define CGI_STATE_OVER_ALL (CGI_STATE_OVER_READ_FROM_CLIENT | CGI_STATE_OVER_READ_FROM_PEER | CGI_STATE_OVER_WRITE_TO_CLIENT | CGI_STATE_OVER_WRITE_TO_PEER) + + struct cgi_state_t { MIO_SVC_HTTS_RSRC_HEADER; @@ -624,16 +635,17 @@ struct cgi_state_t mio_oow_t num_pending_writes_to_peer; mio_dev_pro_t* peer; mio_htrd_t* peer_htrd; - mio_svc_htts_cli_t* cli; + mio_svc_htts_cli_t* client; mio_http_version_t req_version; /* client request */ + unsigned int over: 4; /* must be large enough to accomodate CGI_STATE_OVER_ALL */ + unsigned int keep_alive: 1; unsigned int req_content_length_unlimited: 1; - unsigned int peer_eof: 1; mio_oow_t req_content_length; /* client request content length */ cgi_state_res_mode_t res_mode_to_cli; - mio_dev_sck_on_read_t cli_org_on_read; - mio_dev_sck_on_write_t cli_org_on_write; + mio_dev_sck_on_read_t client_org_on_read; + mio_dev_sck_on_write_t client_org_on_write; }; typedef struct cgi_state_t cgi_state_t; @@ -645,12 +657,12 @@ typedef struct cgi_peer_xtn_t cgi_peer_xtn_t; static void cgi_state_halt_participating_devices (cgi_state_t* cgi_state) { - MIO_ASSERT (cgi_state->cli->htts->mio, cgi_state->cli != MIO_NULL); - MIO_ASSERT (cgi_state->cli->htts->mio, cgi_state->cli->sck != MIO_NULL); + MIO_ASSERT (cgi_state->client->htts->mio, cgi_state->client != MIO_NULL); + MIO_ASSERT (cgi_state->client->htts->mio, cgi_state->client->sck != MIO_NULL); - MIO_DEBUG4 (cgi_state->cli->htts->mio, "HTTS(%p) - halting cgi state %p(client=%p,peer=%p)\n", cgi_state->cli->htts, cgi_state, cgi_state->cli->sck, cgi_state->peer); + MIO_DEBUG4 (cgi_state->client->htts->mio, "HTTS(%p) - halting cgi state %p(client=%p,peer=%p)\n", cgi_state->client->htts, cgi_state, cgi_state->client->sck, cgi_state->peer); - mio_dev_sck_halt (cgi_state->cli->sck); + mio_dev_sck_halt (cgi_state->client->sck); /* check for peer as it may not have been started */ if (cgi_state->peer) mio_dev_pro_halt (cgi_state->peer); @@ -660,8 +672,9 @@ static void cgi_state_halt_participating_devices (cgi_state_t* cgi_state) static int cgi_state_write_to_client (cgi_state_t* cgi_state, const void* data, mio_iolen_t dlen) { +printf ("WRIING TO CLIENT %d\n", dlen); cgi_state->num_pending_writes_to_client++; - if (mio_dev_sck_write(cgi_state->cli->sck, data, dlen, MIO_NULL, MIO_NULL) <= -1) + if (mio_dev_sck_write(cgi_state->client->sck, data, dlen, MIO_NULL, MIO_NULL) <= -1) { cgi_state->num_pending_writes_to_client--; return -1; @@ -676,8 +689,9 @@ static int cgi_state_write_to_client (cgi_state_t* cgi_state, const void* data, static int cgi_state_writev_to_client (cgi_state_t* cgi_state, mio_iovec_t* iov, mio_iolen_t iovcnt) { +printf ("WRITIV TO CLIENT iovcnt = %d\n", (int)iovcnt); cgi_state->num_pending_writes_to_client++; - if (mio_dev_sck_writev(cgi_state->cli->sck, iov, iovcnt, MIO_NULL, MIO_NULL) <= -1) + if (mio_dev_sck_writev(cgi_state->client->sck, iov, iovcnt, MIO_NULL, MIO_NULL) <= -1) { cgi_state->num_pending_writes_to_client--; return -1; @@ -692,6 +706,7 @@ static int cgi_state_writev_to_client (cgi_state_t* cgi_state, mio_iovec_t* iov, static int cgi_state_write_to_peer (cgi_state_t* cgi_state, const void* data, mio_iolen_t dlen) { +printf ("WRIING TO PEER %d\n", (int)dlen); cgi_state->num_pending_writes_to_peer++; if (mio_dev_pro_write(cgi_state->peer, data, dlen, MIO_NULL) <= -1) { @@ -702,14 +717,14 @@ static int cgi_state_write_to_peer (cgi_state_t* cgi_state, const void* data, mi /* TODO: check if it's already finished or something.. */ if (cgi_state->num_pending_writes_to_peer > CGI_STATE_PENDING_IO_THRESHOLD) { - if (mio_dev_sck_read(cgi_state->cli->sck, 0) <= -1) return -1; + if (mio_dev_sck_read(cgi_state->client->sck, 0) <= -1) return -1; } return 0; } static int cgi_state_send_final_status_to_client (cgi_state_t* cgi_state, int status_code) { - mio_svc_htts_cli_t* cli = cgi_state->cli; + mio_svc_htts_cli_t* cli = cgi_state->client; mio_bch_t dtbuf[64]; mio_svc_htts_fmtgmtime (cli->htts, MIO_NULL, dtbuf, MIO_COUNTOF(dtbuf)); @@ -722,6 +737,42 @@ static int cgi_state_send_final_status_to_client (cgi_state_t* cgi_state, int st return cgi_state_write_to_client(cgi_state, MIO_BECS_PTR(cli->sbuf), MIO_BECS_LEN(cli->sbuf)); } +static MIO_INLINE void cgi_state_mark_over (cgi_state_t* cgi_state, int over_bits) +{ + cgi_state->over |= over_bits; + + MIO_DEBUG5 (cgi_state->htts->mio, "HTTS(%p) - client=%p peer=%p new-bits=%x over=%x\n", cgi_state->htts, cgi_state->client->sck, cgi_state->peer, (int)over_bits, (int)cgi_state->over); + + + if (cgi_state->over & CGI_STATE_OVER_READ_FROM_CLIENT) + { + mio_dev_sck_read (cgi_state->client->sck, 0); /* TODO: error handling */ + } + + if (cgi_state->over & CGI_STATE_OVER_READ_FROM_PEER) + { + if (cgi_state->peer) mio_dev_pro_read (cgi_state->peer, MIO_DEV_PRO_OUT, 0); /* TODO: error handling */ + } + + if (cgi_state->over == CGI_STATE_OVER_ALL) + { + /* ready to stop */ + if (cgi_state->peer) mio_dev_pro_halt (cgi_state->peer); + + if (cgi_state->keep_alive) + { + /* how to arrange to delete this cgi_state object and put the socket back to the normal waiting state??? */ +printf ("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"); + + } + else + { + mio_dev_sck_shutdown (cgi_state->client->sck, MIO_DEV_SCK_SHUTDOWN_WRITE); + mio_dev_sck_halt (cgi_state->client->sck); + } + } +} + static void cgi_state_on_kill (cgi_state_t* cgi_state) { printf ("**** CGI_STATE_ON_KILL \n"); @@ -743,19 +794,19 @@ printf ("**** CGI_STATE_ON_KILL \n"); cgi_state->peer_htrd = MIO_NULL; } - if (cgi_state->cli_org_on_read) + if (cgi_state->client_org_on_read) { - cgi_state->cli->sck->on_read = cgi_state->cli_org_on_read; - cgi_state->cli_org_on_read = MIO_NULL; + cgi_state->client->sck->on_read = cgi_state->client_org_on_read; + cgi_state->client_org_on_read = MIO_NULL; } - if (cgi_state->cli_org_on_write) + if (cgi_state->client_org_on_write) { - cgi_state->cli->sck->on_write = cgi_state->cli_org_on_write; - cgi_state->cli_org_on_write = MIO_NULL; + cgi_state->client->sck->on_write = cgi_state->client_org_on_write; + cgi_state->client_org_on_write = MIO_NULL; } - mio_htrd_setrecbs (cgi_state->cli->htrd, &client_htrd_recbs); /* restore the callbacks */ + mio_htrd_setrecbs (cgi_state->client->htrd, &client_htrd_recbs); /* restore the callbacks */ } static void cgi_peer_on_close (mio_dev_pro_t* pro, mio_dev_pro_sid_t sid) @@ -766,32 +817,39 @@ static void cgi_peer_on_close (mio_dev_pro_t* pro, mio_dev_pro_sid_t sid) if (!cgi_state) return; /* cgi state already gone */ -printf (">>>>>>>>> PEER ON CLOSE sid=%d\n", (int)sid); -printf (">> cgi_state %p\n", cgi_state); -printf (">> cgi_state->peer %p\n", cgi_state->peer); -printf (">> cgi_state->cli %p\n", cgi_state->cli); -printf (">> cgi_state->cli->htts %p\n", cgi_state->cli->htts); - - if (sid == MIO_DEV_PRO_MASTER) + switch (sid) { - MIO_DEBUG3 (mio, "HTTS(%p) - peer %p(pid=%d) closing master\n", cgi_state->cli->htts, pro, (int)pro->child_pid); - cgi_peer->state->peer = MIO_NULL; /* clear this peer from the state */ - } - else - { - MIO_ASSERT (mio, cgi_state->peer == pro); + case MIO_DEV_PRO_MASTER: + MIO_DEBUG3 (mio, "HTTS(%p) - peer %p(pid=%d) closing master\n", cgi_state->client->htts, pro, (int)pro->child_pid); + cgi_peer->state->peer = MIO_NULL; /* clear this peer from the state */ + break; - MIO_DEBUG4 (mio, "HTTS(%p) - peer %p(pid=%d) closing slave[%d]\n", cgi_state->cli->htts, pro, (int)pro->child_pid, sid); - if (sid == MIO_DEV_PRO_OUT && !cgi_state->peer_eof) - { -/* check if it's sending... */ - cgi_state->peer_eof = 1; - if (cgi_state->res_mode_to_cli == CGI_STATE_RES_MODE_CHUNKED && - cgi_state_write_to_client(cgi_state, "0\r\n\r\n", 5) <= -1) + case MIO_DEV_PRO_OUT: + MIO_ASSERT (mio, cgi_state->peer == pro); + MIO_DEBUG4 (mio, "HTTS(%p) - peer %p(pid=%d) closing slave[%d]\n", cgi_state->client->htts, pro, (int)pro->child_pid, sid); + + if (!(cgi_state->over & CGI_STATE_OVER_READ_FROM_PEER)) { - cgi_state_halt_participating_devices (cgi_state); + if (cgi_state->res_mode_to_cli == CGI_STATE_RES_MODE_CHUNKED && + cgi_state_write_to_client(cgi_state, "0\r\n\r\n", 5) <= -1) + { + cgi_state_halt_participating_devices (cgi_state); + } + + cgi_state_mark_over (cgi_state, CGI_STATE_OVER_READ_FROM_PEER); } - } + + break; + + case MIO_DEV_PRO_IN: + cgi_state_mark_over (cgi_state, CGI_STATE_OVER_WRITE_TO_PEER); + break; + + case MIO_DEV_PRO_ERR: + default: + MIO_DEBUG4 (mio, "HTTS(%p) - peer %p(pid=%d) closing slave[%d]\n", cgi_state->client->htts, pro, (int)pro->child_pid, sid); + /* do nothing */ + break; } } @@ -806,35 +864,40 @@ static int cgi_peer_on_read (mio_dev_pro_t* pro, mio_dev_pro_sid_t sid, const vo printf (">>>>>>>>> PEER ON READ %d\n", dlen); if (dlen <= -1) { - MIO_DEBUG3 (mio, "HTTPS(%p) - read error from peer %p(pid=%u)\n", cgi_state->cli->htts, pro, (unsigned int)pro->child_pid); + MIO_DEBUG3 (mio, "HTTPS(%p) - read error from peer %p(pid=%u)\n", cgi_state->client->htts, pro, (unsigned int)pro->child_pid); goto oops; } - if (cgi_state->peer_eof) return 0; /* will ignore */ +#if 0 + if (cgi_state->over & CGI_STATE_OVER_READ_FROM_PEER) return 0; /* ignore the read event */ +#endif if (dlen == 0) { - MIO_DEBUG3 (mio, "HTTPS(%p) - EOF from peer %p(pid=%u)\n", cgi_state->cli->htts, pro, (unsigned int)pro->child_pid); - cgi_state->peer_eof = 1; + MIO_DEBUG3 (mio, "HTTPS(%p) - EOF from peer %p(pid=%u)\n", cgi_state->client->htts, pro, (unsigned int)pro->child_pid); if (cgi_state->res_mode_to_cli == CGI_STATE_RES_MODE_CHUNKED && cgi_state_write_to_client(cgi_state, "0\r\n\r\n", 5) <= -1) goto oops; + + cgi_state_mark_over (cgi_state, CGI_STATE_OVER_READ_FROM_PEER); } else { mio_oow_t rem; -printf ( "QQQQQQQQQQQQQQQQQQ>>>>>>>>>>>>>>>>>> feeding to peer htrd.... dlen => %d\n", (int)dlen); + if (mio_htrd_feed(cgi_state->peer_htrd, data, dlen, &rem) <= -1) { printf ( "FEEDING FAILURE TO PEER HTDDRD.. dlen => %d\n", (int)dlen); cgi_state_send_final_status_to_client (cgi_state, 500); /* don't care about error */ goto oops; } + if (rem > 0) { /* If the script specifies Content-Length and produces longer data, it will come here */ - printf ("AAAAAAAAAAAAAAAAAa EEEEEXcessive DATA..................\n"); - cgi_state->peer_eof = 1; /* EOF or use another bit-field? */ +printf ("AAAAAAAAAAAAAAAAAa EEEEEXcessive DATA..................\n"); +/* TODO: or drop this request?? */ + cgi_state_mark_over (cgi_state, CGI_STATE_OVER_READ_FROM_PEER); } } @@ -873,11 +936,12 @@ static int cgi_peer_capture_header (mio_htre_t* req, const mio_bch_t* key, const return 0; } + static int cgi_peer_htrd_peek (mio_htrd_t* htrd, mio_htre_t* req) { cgi_peer_xtn_t* cgi_peer = mio_htrd_getxtn(htrd); cgi_state_t* cgi_state = cgi_peer->state; - mio_svc_htts_cli_t* cli = cgi_state->cli; + mio_svc_htts_cli_t* cli = cgi_state->client; mio_bch_t dtbuf[64]; int status_code; @@ -942,7 +1006,7 @@ static int cgi_peer_htrd_push_content (mio_htrd_t* htrd, mio_htre_t* req, const cgi_peer_xtn_t* cgi_peer = mio_htrd_getxtn(htrd); cgi_state_t* cgi_state = cgi_peer->state; - MIO_ASSERT (cgi_state->cli->htts->mio, htrd == cgi_state->peer_htrd); + MIO_ASSERT (cgi_state->client->htts->mio, htrd == cgi_state->peer_htrd); switch (cgi_state->res_mode_to_cli) { @@ -958,7 +1022,7 @@ static int cgi_peer_htrd_push_content (mio_htrd_t* htrd, mio_htre_t* req, const iov[0].iov_ptr = lbuf; iov[0].iov_len = llen; - iov[1].iov_ptr = data; + iov[1].iov_ptr = (void*)data; iov[1].iov_len = dlen; iov[2].iov_ptr = "\r\n"; iov[2].iov_len = 2; @@ -991,15 +1055,33 @@ static mio_htrd_recbs_t cgi_peer_htrd_recbs = cgi_peer_htrd_push_content }; +static int walk_client_req_trailer (mio_htre_t* req, const mio_bch_t* key, const mio_htre_hdrval_t* val, void* ctx) +{ + printf ("\t%s="); + while (val) + { + printf ("%s ", val->ptr); + val = val->next; + } + printf ("\n"); + return 0; +} + static int cgi_client_htrd_poke (mio_htrd_t* htrd, mio_htre_t* req) { /* client request got completed */ htrd_xtn_t* htrdxtn = mio_htrd_getxtn(htrd); mio_dev_sck_t* sck = htrdxtn->sck; mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(sck); - cgi_state_t* cgi_state = cli->rsrc; + cgi_state_t* cgi_state = (cgi_state_t*)cli->rsrc; + + +printf (">> CLIENT REQUEST COMPLETED\n"); +//mio_htre_walkheaders (req, walk_client_req_trailer, MIO_NULL); +mio_htre_walktrailers (req, walk_client_req_trailer, MIO_NULL); // MIO_HTRD_TRAILERS must be set for this to work /* indicate EOF to the client peer */ + cgi_state_mark_over (cgi_state, CGI_STATE_OVER_READ_FROM_CLIENT); return cgi_state_write_to_peer(cgi_state, MIO_NULL, 0); } @@ -1008,7 +1090,7 @@ static int cgi_client_htrd_push_content (mio_htrd_t* htrd, mio_htre_t* req, cons htrd_xtn_t* htrdxtn = mio_htrd_getxtn(htrd); mio_dev_sck_t* sck = htrdxtn->sck; mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(sck); - cgi_state_t* cgi_state = cli->rsrc; + cgi_state_t* cgi_state = (cgi_state_t*)cli->rsrc; MIO_ASSERT (sck->mio, cli->sck == sck); return cgi_state_write_to_peer(cgi_state, data, dlen); @@ -1024,18 +1106,20 @@ static int cgi_peer_on_write (mio_dev_pro_t* pro, mio_iolen_t wrlen, void* wrctx if (wrlen <= -1) { - MIO_DEBUG3 (mio, "HTTS(%p) - unable to write to peer %p(pid=%u)\n", cgi_state->cli->htts, pro, (int)pro->child_pid); + MIO_DEBUG3 (mio, "HTTS(%p) - unable to write to peer %p(pid=%u)\n", cgi_state->client->htts, pro, (int)pro->child_pid); goto oops; } else if (wrlen == 0) { /* indicated EOF */ /* do nothing here as i didn't incremented num_pending_writes_to_peer when making the write request */ + cgi_state->num_pending_writes_to_peer--; MIO_ASSERT (mio, cgi_state->num_pending_writes_to_peer == 0); - MIO_DEBUG3 (mio, "HTTS(%p) - indicated EOF to peer %p(pid=%u)\n", cgi_state->cli->htts, pro, (int)pro->child_pid); + MIO_DEBUG3 (mio, "HTTS(%p) - indicated EOF to peer %p(pid=%u)\n", cgi_state->client->htts, pro, (int)pro->child_pid); /* indicated EOF to the peer side. i need no more data from the client side. * i don't need to enable input watching in the client side either */ + cgi_state_mark_over (cgi_state, CGI_STATE_OVER_WRITE_TO_PEER); } else { @@ -1044,8 +1128,13 @@ static int cgi_peer_on_write (mio_dev_pro_t* pro, mio_iolen_t wrlen, void* wrctx cgi_state->num_pending_writes_to_peer--; if (cgi_state->num_pending_writes_to_peer == CGI_STATE_PENDING_IO_THRESHOLD) { - // TODO: check if (cli has anything to read...) if so ... - if (mio_dev_sck_read(cgi_state->cli->sck, 1) <= -1) goto oops; + if (!(cgi_state->over & CGI_STATE_OVER_READ_FROM_CLIENT) && + mio_dev_sck_read(cgi_state->client->sck, 1) <= -1) goto oops; + } + + if ((cgi_state->over & CGI_STATE_OVER_READ_FROM_CLIENT) && cgi_state->num_pending_writes_to_peer <= 0) + { + cgi_state_mark_over (cgi_state, CGI_STATE_OVER_WRITE_TO_PEER); } } @@ -1056,12 +1145,11 @@ oops: return 0; } - static int cgi_client_on_read (mio_dev_sck_t* sck, const void* buf, mio_iolen_t len, const mio_skad_t* srcaddr) { mio_t* mio = sck->mio; mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(sck); - cgi_state_t* cgi_state = cli->rsrc; + cgi_state_t* cgi_state = (cgi_state_t*)cli->rsrc; MIO_ASSERT (mio, sck == cli->sck); @@ -1083,24 +1171,16 @@ printf ("** HTTS - cgi client read %p %d -> htts:%p\n", sck, (int)len, cli->h if (len == 0) { /* EOF on the client side. arrange to close */ -printf ("asking pro to close...\n"); -/* HAVE I ALREADY CLOSED IT??? Check conflict is the poke handler */ return cgi_state_write_to_peer(cgi_state, MIO_NULL, 0); } else { mio_oow_t rem; -/* EOF if it got content as long as cgi_state->req_content_length??? */ - if (mio_htrd_feed(cli->htrd, buf, len, &rem) <= -1) - { -printf ("FAILED TO FEED TH CLIENT HTRD......\n"); - goto oops; - } + if (mio_htrd_feed(cli->htrd, buf, len, &rem) <= -1) goto oops; if (rem > 0) { - /* the cgi script is not behaving properly */ -/* giving excessive data... */ +printf ("UUUUUUUUUUUUUUUUUUUUUUUUUUGGGGGHHHHHHHHHHHH .......... CGI CLIENT GIVING EXCESSIVE DATA AFTER CONTENTS...\n"); } } @@ -1116,7 +1196,7 @@ static int cgi_client_on_write (mio_dev_sck_t* sck, mio_iolen_t wrlen, void* wrc { mio_t* mio = sck->mio; mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(sck); - cgi_state_t* cgi_state = cli->rsrc; + cgi_state_t* cgi_state = (cgi_state_t*)cli->rsrc; if (wrlen <= -1) { @@ -1129,29 +1209,26 @@ static int cgi_client_on_write (mio_dev_sck_t* sck, mio_iolen_t wrlen, void* wrc /* if the connect is keep-alive, this part may not be called */ cgi_state->num_pending_writes_to_client--; MIO_ASSERT (mio, cgi_state->num_pending_writes_to_client == 0); - MIO_DEBUG3 (mio, "HTTS(%p) - indicated EOF to client %p(%d)\n", cgi_state->cli->htts, sck, (int)sck->hnd); + MIO_DEBUG3 (mio, "HTTS(%p) - indicated EOF to client %p(%d)\n", cgi_state->client->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 */ + cgi_state_mark_over (cgi_state, CGI_STATE_OVER_WRITE_TO_CLIENT); } else { MIO_ASSERT (mio, cgi_state->num_pending_writes_to_client > 0); - printf ("MANAGED TO WRITE TO CLIENT>... %d\n", (int)wrlen); cgi_state->num_pending_writes_to_client--; if (cgi_state->peer && cgi_state->num_pending_writes_to_client == CGI_STATE_PENDING_IO_THRESHOLD) { - // TODO: check if there is anything to read... */ - if (mio_dev_pro_read(cgi_state->peer, MIO_DEV_PRO_OUT, 1) <= -1) goto oops; + if (!(cgi_state->over & CGI_STATE_OVER_READ_FROM_PEER) && + mio_dev_pro_read(cgi_state->peer, MIO_DEV_PRO_OUT, 1) <= -1) goto oops; } - /* in case the peer died before peer read handler reads EOF */ - if (cgi_state->peer_eof && cgi_state->num_pending_writes_to_client <= 0) + if ((cgi_state->over & CGI_STATE_OVER_READ_FROM_PEER) && cgi_state->num_pending_writes_to_client <= 0) { - /*if (no_more_input is to be read from the client)*/ - cgi_state_halt_participating_devices (cgi_state); // must not use this... must kill the state ... - /* finished writing all */ + cgi_state_mark_over (cgi_state, CGI_STATE_OVER_WRITE_TO_CLIENT); } } @@ -1194,7 +1271,6 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r cgi_state_t* cgi_state = MIO_NULL; cgi_peer_xtn_t* cgi_peer; mio_dev_pro_make_t mi; - int enable_input; /* ensure that you call this function before any contents is received */ MIO_ASSERT (mio, mio_htre_getcontentlen(req) == 0); @@ -1209,14 +1285,14 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r cgi_state = (cgi_state_t*)mio_svc_htts_rsrc_make(htts, MIO_SIZEOF(*cgi_state), cgi_state_on_kill); if (MIO_UNLIKELY(!cgi_state)) goto oops; - cgi_state->cli = cli; + cgi_state->client = cli; /*cgi_state->num_pending_writes_to_client = 0; cgi_state->num_pending_writes_to_peer = 0;*/ cgi_state->req_version = *mio_htre_getversion(req); cgi_state->req_content_length_unlimited = get_request_content_length(req, &cgi_state->req_content_length); - cgi_state->cli_org_on_read = csck->on_read; - cgi_state->cli_org_on_write = csck->on_write; + cgi_state->client_org_on_read = csck->on_read; + cgi_state->client_org_on_write = csck->on_write; csck->on_read = cgi_client_on_read; csck->on_write = cgi_client_on_write; @@ -1287,7 +1363,6 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r goto oops; } - enable_input = 1; #if defined(CGI_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) if (cgi_state->req_content_length_unlimited) { @@ -1299,8 +1374,8 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r /* TODO: must set CONTENT-LENGTH to -1 before start the process */ /* change the callbacks to subscribe to contents to be uploaded */ - cgi_state->cli->htrd->recbs.poke = cgi_client_htrd_poke; - cgi_state->cli->htrd->recbs.push_content = cgi_client_htrd_push_content; + cgi_state->client->htrd->recbs.poke = cgi_client_htrd_poke; + cgi_state->client->htrd->recbs.push_content = cgi_client_htrd_push_content; } else { @@ -1309,26 +1384,36 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r { /* change the callbacks to subscribe to contents to be uploaded */ - cgi_state->cli->htrd->recbs.poke = cgi_client_htrd_poke; - cgi_state->cli->htrd->recbs.push_content = cgi_client_htrd_push_content; + cgi_state->client->htrd->recbs.poke = cgi_client_htrd_poke; + cgi_state->client->htrd->recbs.push_content = cgi_client_htrd_push_content; } else { /* no content to be uploaded from the client */ /* indicate EOF to the peer and disable input wathching from the client */ if (cgi_state_write_to_peer(cgi_state, MIO_NULL, 0) <= -1) goto oops; - enable_input = 0; + cgi_state_mark_over (cgi_state, CGI_STATE_OVER_READ_FROM_CLIENT | CGI_STATE_OVER_WRITE_TO_PEER); } #if defined(CGI_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) } #endif - /* TODO: store current input watching state and use it when destroying the cgi_state data */ - if (mio_dev_sck_read(csck, enable_input) <= -1) goto oops; - - /* this may change later if Content-Length is included in the cgi output */ - cgi_state->res_mode_to_cli = (req->flags & MIO_HTRE_ATTR_KEEPALIVE)? CGI_STATE_RES_MODE_CHUNKED: CGI_STATE_RES_MODE_CLOSE; + if (req->flags & MIO_HTRE_ATTR_KEEPALIVE) + { + cgi_state->keep_alive = 1; + cgi_state->res_mode_to_cli = CGI_STATE_RES_MODE_CHUNKED; + /* the mode still can get switched to CGI_STATE_RES_MODE_LENGTH if the cgi script emits Content-Length */ + } + else + { + cgi_state->keep_alive = 0; + cgi_state->res_mode_to_cli = CGI_STATE_RES_MODE_CLOSE; + } + + /* TODO: store current input watching state and use it when destroying the cgi_state data */ + if (mio_dev_sck_read(csck, !(cgi_state->over & CGI_STATE_OVER_READ_FROM_CLIENT)) <= -1) goto oops; + return 0; oops: diff --git a/mio/lib/mio-sck.h b/mio/lib/mio-sck.h index 3005ce3..af57579 100644 --- a/mio/lib/mio-sck.h +++ b/mio/lib/mio-sck.h @@ -409,6 +409,13 @@ struct mio_dev_sck_t }; +enum mio_dev_sck_shutdown_how_t +{ + MIO_DEV_SCK_SHUTDOWN_READ = (1 << 0), + MIO_DEV_SCK_SHUTDOWN_WRITE = (1 << 1) +}; +typedef enum mio_dev_sck_shutdown_how_t mio_dev_sck_shutdown_how_t; + #ifdef __cplusplus extern "C" { #endif @@ -520,7 +527,6 @@ static MIO_INLINE int mio_dev_sck_timedread (mio_dev_sck_t* sck, int enabled, mi #endif - MIO_EXPORT int mio_dev_sck_setsockopt ( mio_dev_sck_t* dev, int level, @@ -537,7 +543,12 @@ MIO_EXPORT int mio_dev_sck_getsockopt ( mio_scklen_t* optlen ); -MIO_EXPORT mio_uint16_t mio_checksumip ( +MIO_EXPORT int mio_dev_sck_shutdown ( + mio_dev_sck_t* dev, + int how /* bitwise-ORed of mio_dev_sck_shutdown_how_t enumerators */ +); + +MIO_EXPORT mio_uint16_t mio_checksum_ip ( const void* hdr, mio_oow_t len ); diff --git a/mio/lib/mio.c b/mio/lib/mio.c index 56e6e71..019a19a 100644 --- a/mio/lib/mio.c +++ b/mio/lib/mio.c @@ -696,7 +696,9 @@ int mio_exec (mio_t* mio) if (mio_gettmrtmout(mio, MIO_NULL, &tmout) <= -1) { - /* defaults to 1 second if timeout can't be acquired */ + /* defaults to 1 second if timeout can't be acquired. + * if this timeout affects how fast the halted device will get + * killed when there are no events or timer jobs */ tmout.sec = 1; /* TODO: make the default timeout configurable */ tmout.nsec = 0; } diff --git a/mio/lib/pro.c b/mio/lib/pro.c index bbb8226..d55cdbe 100644 --- a/mio/lib/pro.c +++ b/mio/lib/pro.c @@ -546,6 +546,12 @@ static int dev_pro_read_slave (mio_dev_t* dev, void* buf, mio_iolen_t* len, mio_ mio_dev_pro_slave_t* pro = (mio_dev_pro_slave_t*)dev; ssize_t x; + if (MIO_UNLIKELY(pro->pfd == MIO_SYSHND_INVALID)) + { + mio_seterrnum (pro->mio, MIO_EBADHND); + return -1; + } + x = read(pro->pfd, buf, *len); if (x <= -1) { @@ -564,11 +570,22 @@ static int dev_pro_write_slave (mio_dev_t* dev, const void* data, mio_iolen_t* l mio_dev_pro_slave_t* pro = (mio_dev_pro_slave_t*)dev; ssize_t x; + if (MIO_UNLIKELY(pro->pfd == MIO_SYSHND_INVALID)) + { + mio_seterrnum (pro->mio, MIO_EBADHND); + return -1; + } + if (MIO_UNLIKELY(*len <= 0)) { /* this is an EOF indicator */ - mio_dev_halt (dev); /* halt this slave device */ - return 1; + //mio_dev_halt (dev); /* halt this slave device to indicate EOF on the lower-level handle */* + if (MIO_LIKELY(pro->pfd != MIO_SYSHND_INVALID)) /* halt() doesn't close the pipe immediately. so close the underlying pipe */ + { + close (pro->pfd); + pro->pfd = MIO_SYSHND_INVALID; + } + return 1; /* indicate that the operation got successful. the core will execute on_write() with 0. */ } x = write(pro->pfd, data, *len); @@ -589,11 +606,22 @@ static int dev_pro_writev_slave (mio_dev_t* dev, const mio_iovec_t* iov, mio_iol mio_dev_pro_slave_t* pro = (mio_dev_pro_slave_t*)dev; ssize_t x; + if (MIO_UNLIKELY(pro->pfd == MIO_SYSHND_INVALID)) + { + mio_seterrnum (pro->mio, MIO_EBADHND); + return -1; + } + if (MIO_UNLIKELY(*iovcnt <= 0)) { /* this is an EOF indicator */ - mio_dev_halt (dev); /* halt this slave device */ - return 1; + /*mio_dev_halt (dev);*/ /* halt this slave device to indicate EOF on the lower-level handle */ + if (MIO_LIKELY(pro->pfd != MIO_SYSHND_INVALID)) /* halt() doesn't close the pipe immediately. so close the underlying pipe */ + { + close (pro->pfd); + pro->pfd = MIO_SYSHND_INVALID; + } + return 1; /* indicate that the operation got successful. the core will execute on_write() with 0. */ } x = writev(pro->pfd, iov, *iovcnt); diff --git a/mio/lib/sck.c b/mio/lib/sck.c index 195849f..a015e8c 100644 --- a/mio/lib/sck.c +++ b/mio/lib/sck.c @@ -1716,14 +1716,37 @@ int mio_dev_sck_getsockopt (mio_dev_sck_t* dev, int level, int optname, void* op return getsockopt(dev->hnd, level, optname, optval, optlen); } +int mio_dev_sck_shutdown (mio_dev_sck_t* dev, int how) +{ + switch (how & (MIO_DEV_SCK_SHUTDOWN_READ | MIO_DEV_SCK_SHUTDOWN_WRITE)) + { + case (MIO_DEV_SCK_SHUTDOWN_READ | MIO_DEV_SCK_SHUTDOWN_WRITE): + how = SHUT_RDWR; + break; + + case MIO_DEV_SCK_SHUTDOWN_READ: + how = SHUT_RD; + break; + + case MIO_DEV_SCK_SHUTDOWN_WRITE: + how = SHUT_WR; + break; + + default: + mio_seterrnum (dev->mio, MIO_EINVAL); + return -1; + } + + return shutdown(dev->hnd, how); +} + /* ========================================================================= */ -mio_uint16_t mio_checksumip (const void* hdr, mio_oow_t len) +mio_uint16_t mio_checksum_ip (const void* hdr, mio_oow_t len) { mio_uint32_t sum = 0; mio_uint16_t *ptr = (mio_uint16_t*)hdr; - while (len > 1) { sum += *ptr++; diff --git a/mio/t/t1.txt b/mio/t/t1.txt new file mode 100644 index 0000000..62f8848 --- /dev/null +++ b/mio/t/t1.txt @@ -0,0 +1,13 @@ +POST /home/hyung-hwan/projects/mio/t/b.sh HTTP/1.1 +Host: abc.txt +Content-Type: text/plain +Transfer-Encoding: chunked + +7 +Mozilla +9 +Developer +7 +Network +0 + diff --git a/mio/t/t2.txt b/mio/t/t2.txt new file mode 100644 index 0000000..d2ea8e6 --- /dev/null +++ b/mio/t/t2.txt @@ -0,0 +1,15 @@ +GET /home/hyung-hwan/projects/mio/t/b.sh HTTP/1.1 +Host: abc.txt +Transfer-Encoding: chunked +Connection: close +Trailer: Content-Type + +7 +Mozilla +9 +Developer +7 +Network +0 +Content-Type: text/plain + diff --git a/mio/t/t3.txt b/mio/t/t3.txt new file mode 100644 index 0000000..95e92bd --- /dev/null +++ b/mio/t/t3.txt @@ -0,0 +1,13 @@ +POST /home/hyung-hwan/projects/mio/t/b.sh HTTP/1.0 +Host: abc.txt +Content-Type: text/plain +Transfer-Encoding: chunked + +7 +Mozilla +9 +Developer +7 +Network +0 +