From d95bc9bc92a0e9fd9b3d3009d604d70db3bb39d2 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Wed, 20 May 2020 10:25:12 +0000 Subject: [PATCH] in the midst of debugging http server code --- mio/lib/htrd.c | 12 +- mio/lib/http-svr.c | 282 ++++++++++++++++++++++++++++----------------- mio/lib/mio-http.h | 4 +- mio/lib/mio-pro.h | 7 ++ mio/lib/mio.c | 10 +- mio/lib/path.c | 4 +- mio/lib/pro.c | 26 +++-- mio/t/b.sh | 2 + mio/t/d.sh | 6 +- mio/t/e.sh | 22 ++++ mio/t/http1.hawk | 6 +- 11 files changed, 253 insertions(+), 128 deletions(-) create mode 100755 mio/t/e.sh diff --git a/mio/lib/htrd.c b/mio/lib/htrd.c index 431454b..1348aab 100644 --- a/mio/lib/htrd.c +++ b/mio/lib/htrd.c @@ -377,7 +377,7 @@ static mio_bch_t* parse_initial_line (mio_htrd_t* htrd, mio_bch_t* line) #else while (*p != '\0' && !is_space_octet(*p)) { - if (*p == '?' && param.ptr == MIO_NULL) + if (*p == '?' && !param.ptr) { tmp.len = p - tmp.ptr; /* length of the path part */ *p++ = '\0'; /* null-terminate the path part */ @@ -388,7 +388,15 @@ static mio_bch_t* parse_initial_line (mio_htrd_t* htrd, mio_bch_t* line) /* the url must be followed by a space */ if (!is_space_octet(*p)) goto badre; - param.len = p - param.ptr; /* length of the param part */ + if (param.ptr) + { + param.len = p - param.ptr; /* length of the param part */ + } + else + { + tmp.len = p - tmp.ptr; + param.len = 0; + } *p = '\0'; /* null-terminate the path or param part */ if (param.ptr) diff --git a/mio/lib/http-svr.c b/mio/lib/http-svr.c index a89b0d4..daf174c 100644 --- a/mio/lib/http-svr.c +++ b/mio/lib/http-svr.c @@ -9,6 +9,7 @@ #include #include #include +#include /* setenv */ #define CGI_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH @@ -113,6 +114,8 @@ static int process_request (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_ * the decoded query path is made available in the * non-peek mode as well */ + MIO_DEBUG2 (htts->mio, "[RAW-REQ] %s %s\n", mio_htre_getqmethodname(req), mio_htre_getqpath(req)); + mio_htre_perdecqpath(req); /* TODO: proper request logging */ @@ -180,7 +183,7 @@ if (mio_htre_getcontentlen(req) > 0) mio_htre_discardcontent (req); /* 411 Length Required - can't keep alive. Force disconnect */ req->flags &= ~MIO_HTRE_ATTR_KEEPALIVE; /* to cause sendstatus() to close */ - if (mio_svc_htts_sendstatus(htts, csck, req, 411, MIO_NULL) <= -1) mio_dev_sck_halt (csck); /*TODO: redo this sendstatus */ + if (mio_svc_htts_sendstatus(htts, csck, req, 411, MIO_NULL) <= -1) goto oops; } else @@ -189,35 +192,6 @@ if (mio_htre_getcontentlen(req) > 0) /*const mio_bch_t* qpath = mio_htre_getqpath(req);*/ if (mio_svc_htts_docgi(htts, csck, req, "") <= -1) goto oops; -#if 0 -/* - if (mio_comp_bcstr(qpath, "/testfunc", 0) == 0) - { - if (mio_svc_htts_sendcgi(htts, csck, test_func_handler, req) <= -1) - { - mio_htre_discardcontent (req); - mio_dev_sck_halt (csck); - } - } - else */if (mio_svc_htts_sendfile(htts, csck, qpath, 200, mth, mio_htre_getversion(req), (req->flags & MIO_HTRE_ATTR_KEEPALIVE)) <= -1) - { - mio_htre_discardcontent (req); - mio_dev_sck_halt (csck); - } - - } - } - - if (!(req->flags & MIO_HTRE_ATTR_KEEPALIVE) || mth == MIO_HTTP_CONNECT) - { - if (!peek) - { -//// task = mio_htts_entaskdisconnect(htts, client, MIO_NULL); -//// if (MIO_UNLIKELY(!task)) goto oops; - } - } -#endif - return 0; oops: @@ -289,7 +263,6 @@ static void fini_client (mio_svc_htts_cli_t* cli) if (cli->rsrc) { -printf ("TRYING TO KILL RSRC IN VARIABLE - ADDRESS %p\n", &cli->rsrc); mio_svc_htts_rsrc_kill (cli->rsrc); cli->rsrc = MIO_NULL; } @@ -333,18 +306,19 @@ static int listener_on_read (mio_dev_sck_t* sck, const void* buf, mio_iolen_t le if (len <= -1) { - MIO_DEBUG3 (mio, "HTTS(%p) - unable to read client socket %p(%d)\n", cli->htts, sck, (int)sck->hnd); + MIO_DEBUG3 (mio, "HTTS(%p) - unable to read client %p(%d)\n", cli->htts, sck, (int)sck->hnd); goto oops; } - if (len == 0) goto oops; + if (len == 0) + { + MIO_DEBUG3 (mio, "HTTS(%p) - EOF on client %p(%d)\n", cli->htts, sck, (int)sck->hnd); + goto oops; + } if ((x = mio_htrd_feed(cli->htrd, buf, len, &rem)) <= -1) { -/* in some cases, we may have to send some http response depending on the failure type */ -/* BADRE -> bad request? */ printf ("** HTTS - client htrd feed failure socket(%p) - %d\n", sck, x); - /* TODO: either send bad request or server failure ... */ goto oops; } @@ -363,6 +337,7 @@ printf ("** HTTS - client htrd feed failure socket(%p) - %d\n", sck, x); return 0; oops: +printf ("HALTING CLIENT SOCKEXXT %p\n", sck); mio_dev_sck_halt (sck); return 0; } @@ -401,63 +376,64 @@ static void listener_on_connect (mio_dev_sck_t* sck) static void listener_on_disconnect (mio_dev_sck_t* sck) { + mio_t* mio = sck->mio; mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(sck); switch (MIO_DEV_SCK_GET_PROGRESS(sck)) { case MIO_DEV_SCK_CONNECTING: /* only for connecting sockets */ - MIO_DEBUG1 (sck->mio, "OUTGOING SESSION DISCONNECTED - FAILED TO CONNECT (%d) TO REMOTE SERVER\n", (int)sck->hnd); + MIO_DEBUG1 (mio, "OUTGOING SESSION DISCONNECTED - FAILED TO CONNECT (%d) TO REMOTE SERVER\n", (int)sck->hnd); break; case MIO_DEV_SCK_CONNECTING_SSL: /* only for connecting sockets */ - MIO_DEBUG1 (sck->mio, "OUTGOING SESSION DISCONNECTED - FAILED TO SSL-CONNECT (%d) TO REMOTE SERVER\n", (int)sck->hnd); + MIO_DEBUG1 (mio, "OUTGOING SESSION DISCONNECTED - FAILED TO SSL-CONNECT (%d) TO REMOTE SERVER\n", (int)sck->hnd); break; case MIO_DEV_SCK_CONNECTED: /* only for connecting sockets */ - MIO_DEBUG1 (sck->mio, "OUTGOING CLIENT CONNECTION GOT TORN DOWN %p(%d).......\n", (int)sck->hnd); + MIO_DEBUG1 (mio, "OUTGOING CLIENT CONNECTION GOT TORN DOWN %p(%d).......\n", (int)sck->hnd); break; case MIO_DEV_SCK_LISTENING: - MIO_DEBUG2 (sck->mio, "LISTNER SOCKET %p(%d) - SHUTTUING DOWN\n", sck, (int)sck->hnd); + MIO_DEBUG2 (mio, "LISTNER SOCKET %p(%d) - SHUTTUING DOWN\n", sck, (int)sck->hnd); break; case MIO_DEV_SCK_ACCEPTING_SSL: /* special case. */ /* this progress code indicates that the ssl-level accept failed. * on_disconnected() with this code is called without corresponding on_connect(). * the cli extension are is not initialized yet */ - MIO_ASSERT (sck->mio, sck != cli->sck); - MIO_ASSERT (sck->mio, cli->sck == cli->htts->lsck); /* the field is a copy of the extension are of the listener socket. so it should point to the listner socket */ - MIO_DEBUG2 (sck->mio, "LISTENER UNABLE TO SSL-ACCEPT CLIENT %p(%d) ....%p\n", sck, (int)sck->hnd); + MIO_ASSERT (mio, sck != cli->sck); + MIO_ASSERT (mio, cli->sck == cli->htts->lsck); /* the field is a copy of the extension are of the listener socket. so it should point to the listner socket */ + MIO_DEBUG2 (mio, "LISTENER UNABLE TO SSL-ACCEPT CLIENT %p(%d) ....%p\n", sck, (int)sck->hnd); return; case MIO_DEV_SCK_ACCEPTED: /* only for sockets accepted by the listeners. will never come here because * the disconnect call for such sockets have been changed in listener_on_connect() */ - MIO_DEBUG2 (sck->mio, "ACCEPTED CLIENT SOCKET %p(%d) GOT DISCONNECTED.......\n", sck, (int)sck->hnd); + MIO_DEBUG2 (mio, "ACCEPTED CLIENT SOCKET %p(%d) GOT DISCONNECTED.......\n", sck, (int)sck->hnd); break; default: - MIO_DEBUG2 (sck->mio, "SOCKET %p(%d) DISCONNECTED AFTER ALL.......\n", sck, (int)sck->hnd); + MIO_DEBUG2 (mio, "SOCKET %p(%d) DISCONNECTED AFTER ALL.......\n", sck, (int)sck->hnd); break; } if (sck == cli->htts->lsck) { /* the listener socket has these fields set to NULL */ - MIO_ASSERT (sck->mio, cli->htrd == MIO_NULL); - MIO_ASSERT (sck->mio, cli->sbuf == MIO_NULL); + MIO_ASSERT (mio, cli->htrd == MIO_NULL); + MIO_ASSERT (mio, cli->sbuf == MIO_NULL); - MIO_DEBUG2 (sck->mio, "HTTS(%p) - listener socket disconnect %p\n", cli->htts, sck); + MIO_DEBUG2 (mio, "HTTS(%p) - listener socket disconnect %p\n", cli->htts, sck); cli->htts->lsck = MIO_NULL; /* let the htts service forget about this listening socket */ } else { /* client socket */ - MIO_DEBUG2 (sck->mio, "HTTS(%p) - client socket disconnect %p\n", cli->htts, sck); - MIO_ASSERT (sck->mio, cli->sck == sck); + MIO_DEBUG2 (mio, "HTTS(%p) - client socket disconnect %p\n", cli->htts, sck); + MIO_ASSERT (mio, cli->sck == sck); fini_client (cli); } } @@ -653,12 +629,14 @@ struct cgi_state_t 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 ever_attempted_to_write_to_client; + unsigned int ever_attempted_to_write_to_client: 1; + unsigned int client_disconnected: 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 client_org_on_read; mio_dev_sck_on_write_t client_org_on_write; + mio_dev_sck_on_disconnect_t client_org_on_disconnect; }; typedef struct cgi_state_t cgi_state_t; @@ -673,14 +651,12 @@ static void cgi_state_halt_participating_devices (cgi_state_t* cgi_state) 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->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_DEBUG4 (cgi_state->client->htts->mio, "HTTS(%p) - Halting participating devices in 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->client->sck); /* check for peer as it may not have been started */ if (cgi_state->peer) mio_dev_pro_halt (cgi_state->peer); - -/* TODO: when to destroy cgi_state? */ - } static int cgi_state_write_to_client (cgi_state_t* cgi_state, const void* data, mio_iolen_t dlen) @@ -719,6 +695,16 @@ static int cgi_state_writev_to_client (cgi_state_t* cgi_state, mio_iovec_t* iov, return 0; } +static int cgi_state_write_last_chunk_to_client (cgi_state_t* 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) return -1; + + if (!cgi_state->keep_alive && cgi_state_write_to_client(cgi_state, MIO_NULL, 0) <= -1) return -1; + + return 0; +} + static int cgi_state_write_to_peer (cgi_state_t* cgi_state, const void* data, mio_iolen_t dlen) { cgi_state->num_pending_writes_to_peer++; @@ -763,12 +749,12 @@ static MIO_INLINE void cgi_state_mark_over (cgi_state_t* cgi_state, int over_bit if (!(old_over & CGI_STATE_OVER_READ_FROM_CLIENT) && (cgi_state->over & CGI_STATE_OVER_READ_FROM_CLIENT)) { - mio_dev_sck_read (cgi_state->client->sck, 0); /* TODO: error handling */ + if (mio_dev_sck_read(cgi_state->client->sck, 0) <= -1) mio_dev_sck_halt (cgi_state->client->sck); } if (!(old_over & CGI_STATE_OVER_READ_FROM_PEER) && (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->peer && mio_dev_pro_read(cgi_state->peer, MIO_DEV_PRO_OUT, 0) <= -1) mio_dev_pro_halt (cgi_state->peer); } if (old_over != CGI_STATE_OVER_ALL && cgi_state->over == CGI_STATE_OVER_ALL) @@ -779,11 +765,11 @@ static MIO_INLINE void cgi_state_mark_over (cgi_state_t* cgi_state, int over_bit if (cgi_state->keep_alive) { /* how to arrange to delete this cgi_state object and put the socket back to the normal waiting state??? */ - MIO_ASSERT (cgi_state->htts->mio, cgi_state->client->rsrc == cgi_state); + MIO_ASSERT (cgi_state->htts->mio, cgi_state->client->rsrc == (mio_svc_htts_rsrc_t*)cgi_state); -printf ("DEASSIGNING FROM THE MAIN CLIENT RSRC... state -> %p VARIABEL ADDRESSS %p\n", cgi_state->client->rsrc, &cgi_state->client->rsrc); - MIO_SVC_HTTS_RSRC_DEASSIGN (cgi_state->client->rsrc); -printf ("AFTER DEASSIGNING FROM THE MAIN CLIENT RSRC... state -> %p VARIABEL ADDRESSS %p\n", cgi_state->client->rsrc, &cgi_state->client->rsrc); +printf ("DETACHING FROM THE MAIN CLIENT RSRC... state -> %p\n", cgi_state->client->rsrc); + MIO_SVC_HTTS_RSRC_DETACH (cgi_state->client->rsrc); + /* cgi_state must not be access from here down as it could have been destroyed */ } else { @@ -826,11 +812,26 @@ printf ("**** CGI_STATE_ON_KILL \n"); cgi_state->client_org_on_write = MIO_NULL; } - mio_htrd_setrecbs (cgi_state->client->htrd, &client_htrd_recbs); /* restore the callbacks */ - if (mio_dev_sck_read (cgi_state->client->sck, 1) <= -1) + + if (cgi_state->client_org_on_disconnect) { - mio_dev_sck_halt (cgi_state->client->sck); + cgi_state->client->sck->on_disconnect = cgi_state->client_org_on_disconnect; + cgi_state->client_org_on_disconnect = MIO_NULL; } + + mio_htrd_setrecbs (cgi_state->client->htrd, &client_htrd_recbs); /* restore the callbacks */ + + if (!cgi_state->client_disconnected) + { +printf ("ENABLING INPUT WATCHING on CLIENT %p. \n", cgi_state->client->sck); + if (!cgi_state->keep_alive || mio_dev_sck_read(cgi_state->client->sck, 1) <= -1) + { +printf ("FAILED TO ENABLE INPUT WATCHING on CLINET %p. SO HALTING CLIENT SOCKET>>>>>>>>>>>>>\n", cgi_state->client->sck); + mio_dev_sck_halt (cgi_state->client->sck); + } + } + +printf ("**** CGI_STATE_ON_KILL DONE\n"); } static void cgi_peer_on_close (mio_dev_pro_t* pro, mio_dev_pro_sid_t sid) @@ -846,8 +847,21 @@ static void cgi_peer_on_close (mio_dev_pro_t* pro, mio_dev_pro_sid_t sid) 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_state->peer = MIO_NULL; /* clear this peer from the state */ -printf ("DEASSIGNING 11.....................%p %d\n", cgi_peer->state, (int)cgi_peer->state->rsrc_refcnt); - MIO_SVC_HTTS_RSRC_DEASSIGN (cgi_peer->state); + + MIO_ASSERT (mio, cgi_peer->state != MIO_NULL); +printf ("DETACHING FROM CGI PEER DEVICE.....................%p %d\n", cgi_peer->state, (int)cgi_peer->state->rsrc_refcnt); + MIO_SVC_HTTS_RSRC_DETACH (cgi_peer->state); + + if (cgi_state->peer_htrd) + { + /* once this peer device is closed, peer's htrd is also never used. + * it's safe to detach the extra information attached on the htrd object. */ + cgi_peer = mio_htrd_getxtn(cgi_state->peer_htrd); + MIO_ASSERT (mio, cgi_peer->state != MIO_NULL); +printf ("DETACHING FROM CGI PEER HTRD.....................%p %d\n", cgi_peer->state, (int)cgi_peer->state->rsrc_refcnt); + MIO_SVC_HTTS_RSRC_DETACH (cgi_peer->state); + } + break; case MIO_DEV_PRO_OUT: @@ -856,15 +870,11 @@ printf ("DEASSIGNING 11.....................%p %d\n", cgi_peer->state, (int)cg if (!(cgi_state->over & CGI_STATE_OVER_READ_FROM_PEER)) { - 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) - { + if (cgi_state_write_last_chunk_to_client(cgi_state) <= -1) cgi_state_halt_participating_devices (cgi_state); - } - - cgi_state_mark_over (cgi_state, CGI_STATE_OVER_READ_FROM_PEER); + else + cgi_state_mark_over (cgi_state, CGI_STATE_OVER_READ_FROM_PEER); } - break; case MIO_DEV_PRO_IN: @@ -903,16 +913,8 @@ static int cgi_peer_on_read (mio_dev_pro_t* pro, mio_dev_pro_sid_t sid, const vo /* the cgi script could be misbehaviing. * it still has to read more but EOF is read. * otherwise client_peer_htrd_poke() should have been called */ - - 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; - + if (cgi_state_write_last_chunk_to_client(cgi_state) <= -1) goto oops; cgi_state_mark_over (cgi_state, CGI_STATE_OVER_READ_FROM_PEER); - -printf ("DEASSIGNING 33.....................peer %p state %p %d\n", cgi_peer, cgi_peer->state, (int)cgi_peer->state->rsrc_refcnt); - /* peer_htrd isn't needed any longer. unlink the cgi state from it */ - cgi_peer = mio_htrd_getxtn(cgi_state->peer_htrd); - MIO_SVC_HTTS_RSRC_DEASSIGN (cgi_peer->state); } } else @@ -924,9 +926,14 @@ printf ("DEASSIGNING 33.....................peer %p state %p %d\n", cgi_peer, if (mio_htrd_feed(cgi_state->peer_htrd, data, dlen, &rem) <= -1) { MIO_DEBUG3 (mio, "HTTPS(%p) - unable to feed peer into to htrd - peer %p(pid=%u)\n", cgi_state->htts, pro, (unsigned int)pro->child_pid); + if (!cgi_state->ever_attempted_to_write_to_client && - !(cgi_state->over & CGI_STATE_OVER_WRITE_TO_CLIENT) && - cgi_state_send_final_status_to_client(cgi_state, 500) <= -1) goto oops; + !(cgi_state->over & CGI_STATE_OVER_WRITE_TO_CLIENT)) + { + cgi_state_send_final_status_to_client (cgi_state, 500); /* don't care about error because it jumps to oops below anyway */ + } + + goto oops; } if (rem > 0) @@ -935,14 +942,6 @@ printf ("DEASSIGNING 33.....................peer %p state %p %d\n", cgi_peer, printf ("AAAAAAAAAAAAAAAAAa EEEEEXcessive DATA..................\n"); /* TODO: or drop this request?? */ } - - if (cgi_state->over & CGI_STATE_OVER_READ_FROM_PEER) - { -printf ("DEASSIGNING 22.....................peer %p state %p %d\n", cgi_peer, cgi_peer->state, (int)cgi_peer->state->rsrc_refcnt); - /* peer_htrd isn't needed any longer. unlink the cgi state from it */ - cgi_peer = mio_htrd_getxtn(cgi_state->peer_htrd); - MIO_SVC_HTTS_RSRC_DEASSIGN (cgi_peer->state); - } } return 0; @@ -1026,9 +1025,7 @@ printf ("CGI PEER HTRD PEEK...\n"); break; case CGI_STATE_RES_MODE_LENGTH: - /* TODO: Keep-Alive if explicit in http/1.0 . - * Keep-Alive not needed if http/1.1 or later */ - break; + if (mio_becs_cat(cli->sbuf, (cgi_state->keep_alive? "Connection: keep-alive\r\n": "Connection: close\r\n")) == (mio_oow_t)-1) return -1; } if (mio_becs_cat(cli->sbuf, "\r\n") == (mio_oow_t)-1) return -1; @@ -1043,11 +1040,7 @@ static int cgi_peer_htrd_poke (mio_htrd_t* htrd, mio_htre_t* req) printf (">> PEER RESPONSE COMPLETED\n"); - 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) return -1; - - /* indicate EOF to the client */ - if (cgi_state_write_to_client(cgi_state, MIO_NULL, 0) <= -1) return -1; + if (cgi_state_write_last_chunk_to_client(cgi_state) <= -1) return -1; cgi_state_mark_over (cgi_state, CGI_STATE_OVER_READ_FROM_PEER); return 0; @@ -1198,6 +1191,14 @@ oops: return 0; } +static void cgi_client_on_disconnect (mio_dev_sck_t* sck) +{ + mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(sck); + cgi_state_t* cgi_state = (cgi_state_t*)cli->rsrc; + cgi_state->client_disconnected = 1; + listener_on_disconnect (sck); +} + 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; @@ -1324,6 +1325,71 @@ static MIO_INLINE int get_request_content_length (mio_htre_t* req, mio_oow_t* le return 0; /* limited to the length set in *len */ } +struct cgi_peer_fork_ctx_t +{ + mio_svc_htts_cli_t* cli; + mio_htre_t* req; + const mio_bch_t* docroot; +}; +typedef struct cgi_peer_fork_ctx_t cgi_peer_fork_ctx_t; + +static int cgi_peer_on_fork (mio_dev_pro_t* pro, void* fork_ctx) +{ + /*mio_t* mio = pro->mio;*/ /* in this callback, the pro device is not fully up. however, the mio field is guaranteed to be available */ + cgi_peer_fork_ctx_t* fc = (cgi_peer_fork_ctx_t*)fork_ctx; + mio_oow_t content_length; + mio_bch_t tmp[128]; + const mio_bch_t* qparam; + + qparam = mio_htre_getqparam(fc->req); + + clearenv (); + + setenv ("GATEWAY_INTERFACE", "CGI/1.1", 1); + +///////// +printf (">>>>>>>>>> %d pro->mio %p\n", + mio_fmttobcstr (pro->mio, tmp, MIO_COUNTOF(tmp), "HTTP/%d.%d", (int)mio_htre_getmajorversion(fc->req), (int)mio_htre_getminorversion(fc->req)), pro->mio); +//////// + + setenv ("SERVER_PROTOCOL", tmp, 1); + + //setenv ("SCRIPT_FILENAME", + //setenv ("SCRIPT_NAME", + setenv ("DOCUMENT_ROOT", fc->docroot, 1); + + setenv ("REQUEST_METHOD", mio_htre_getqmethodname(fc->req), 1); + setenv ("REQUEST_URI", mio_htre_getqpath(fc->req), 1); + if (qparam) setenv ("QUERY_STRING", qparam, 1); + + if (get_request_content_length(fc->req, &content_length) == 0) + { + + mio_fmt_uintmax_to_bcstr(tmp, MIO_COUNTOF(tmp), content_length, 10, 0, '\0', MIO_NULL); + setenv ("CONTENT_LENGTH", tmp, 1); + } + else + { + /* content length unknown, neither is it 0 - this is not standard */ + setenv ("CONTENT_LENGTH", "-1", 1); + } + setenv ("SERVER_SOFTWARE", fc->cli->htts->server_name, 1); +#if 0 + setenv ("SERVER_PORT", + setenv ("SERVER_ADDR", + setenv ("SERVER_NAME", /* server host name */ + + setenv ("REMOTE_PORT", + setenv ("REMOTE_ADDR", +#endif + + //mio_htre_walkheaders(req, + /* [NOTE] trailers are not available when this cgi resource is started. let's not call mio_htre_walktrailers() */ + + return 0; +} + + int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req, const mio_bch_t* docroot) { mio_t* mio = htts->mio; @@ -1331,16 +1397,24 @@ 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; + cgi_peer_fork_ctx_t fc; /* ensure that you call this function before any contents is received */ MIO_ASSERT (mio, mio_htre_getcontentlen(req) == 0); + MIO_MEMSET (&fc, 0, MIO_SIZEOF(fc)); + fc.cli = cli; + fc.req = req; + fc.docroot = docroot; + MIO_MEMSET (&mi, 0, MIO_SIZEOF(mi)); mi.flags = MIO_DEV_PRO_READOUT | MIO_DEV_PRO_ERRTONUL | MIO_DEV_PRO_WRITEIN /*| MIO_DEV_PRO_FORGET_CHILD*/; mi.cmd = mio_htre_getqpath(req); /* TODO: combine it with docroot */ mi.on_read = cgi_peer_on_read; mi.on_write = cgi_peer_on_write; mi.on_close = cgi_peer_on_close; + mi.on_fork = cgi_peer_on_fork; + mi.fork_ctx = &fc; 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; @@ -1353,11 +1427,13 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r cgi_state->client_org_on_read = csck->on_read; cgi_state->client_org_on_write = csck->on_write; + cgi_state->client_org_on_disconnect = csck->on_disconnect; csck->on_read = cgi_client_on_read; csck->on_write = cgi_client_on_write; + csck->on_disconnect = cgi_client_on_disconnect; MIO_ASSERT (mio, cli->rsrc == MIO_NULL); - MIO_SVC_HTTS_RSRC_ASSIGN (cgi_state, cli->rsrc); + MIO_SVC_HTTS_RSRC_ATTACH (cgi_state, cli->rsrc); /* TODO: create cgi environment variables... */ /* TODO: @@ -1372,7 +1448,7 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r cgi_state->peer = mio_dev_pro_make(mio, MIO_SIZEOF(*cgi_peer), &mi); if (MIO_UNLIKELY(!cgi_state->peer)) goto oops; cgi_peer = mio_dev_pro_getxtn(cgi_state->peer); - MIO_SVC_HTTS_RSRC_ASSIGN (cgi_state, cgi_peer->state); + MIO_SVC_HTTS_RSRC_ATTACH (cgi_state, cgi_peer->state); cgi_state->peer_htrd = mio_htrd_open(mio, MIO_SIZEOF(*cgi_peer)); if (MIO_UNLIKELY(!cgi_state->peer_htrd)) goto oops; @@ -1380,7 +1456,7 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r mio_htrd_setrecbs (cgi_state->peer_htrd, &cgi_peer_htrd_recbs); cgi_peer = mio_htrd_getxtn(cgi_state->peer_htrd); - MIO_SVC_HTTS_RSRC_ASSIGN (cgi_state, cgi_peer->state); + MIO_SVC_HTTS_RSRC_ATTACH (cgi_state, cgi_peer->state); #if !defined(CGI_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH) if (cgi_state->req_content_length_unlimited) diff --git a/mio/lib/mio-http.h b/mio/lib/mio-http.h index 4fe26e6..65832dc 100644 --- a/mio/lib/mio-http.h +++ b/mio/lib/mio-http.h @@ -178,8 +178,8 @@ struct mio_svc_htts_rsrc_t MIO_SVC_HTTS_RSRC_HEADER; }; -#define MIO_SVC_HTTS_RSRC_ASSIGN(rsrc, var) do { (var) = (rsrc); ++(rsrc)->rsrc_refcnt; } while(0) -#define MIO_SVC_HTTS_RSRC_DEASSIGN(rsrc_var) do { if (--(rsrc_var)->rsrc_refcnt == 0) { mio_svc_htts_rsrc_t* __rsrc_tmp = (rsrc_var); (rsrc_var) = MIO_NULL; mio_svc_htts_rsrc_kill(__rsrc_tmp); } else { (rsrc_var) = MIO_NULL; } } while(0) +#define MIO_SVC_HTTS_RSRC_ATTACH(rsrc, var) do { (var) = (rsrc); ++(rsrc)->rsrc_refcnt; } while(0) +#define MIO_SVC_HTTS_RSRC_DETACH(rsrc_var) do { if (--(rsrc_var)->rsrc_refcnt == 0) { mio_svc_htts_rsrc_t* __rsrc_tmp = (rsrc_var); (rsrc_var) = MIO_NULL; mio_svc_htts_rsrc_kill(__rsrc_tmp); } else { (rsrc_var) = MIO_NULL; } } while(0) /* -------------------------------------------------------------- */ #if defined(__cplusplus) diff --git a/mio/lib/mio-pro.h b/mio/lib/mio-pro.h index 976e4ac..6e76754 100644 --- a/mio/lib/mio-pro.h +++ b/mio/lib/mio-pro.h @@ -59,6 +59,11 @@ typedef void (*mio_dev_pro_on_close_t) ( mio_dev_pro_sid_t sid ); +typedef int (*mio_dev_pro_on_fork_t) ( + mio_dev_pro_t* dev, + void* fork_ctx +); + struct mio_dev_pro_t { MIO_DEV_HEADER; @@ -121,6 +126,8 @@ struct mio_dev_pro_make_t mio_dev_pro_on_write_t on_write; /* mandatory */ mio_dev_pro_on_read_t on_read; /* mandatory */ mio_dev_pro_on_close_t on_close; /* optional */ + mio_dev_pro_on_fork_t on_fork; /* optional */ + void* fork_ctx; }; diff --git a/mio/lib/mio.c b/mio/lib/mio.c index 422075f..8292faf 100644 --- a/mio/lib/mio.c +++ b/mio/lib/mio.c @@ -1037,7 +1037,7 @@ int mio_dev_watch (mio_dev_t* dev, mio_dev_watch_cmd_t cmd, int events) * mio_dev_wtach (dev, MIO_DEV_WATCH_RENEW, 0); */ if (MIO_WQ_IS_EMPTY(&dev->wq)) events &= ~MIO_DEV_EVENT_OUT; else events |= MIO_DEV_EVENT_OUT; - + /* fall through */ case MIO_DEV_WATCH_UPDATE: /* honor event watching requests as given by the caller */ @@ -1045,17 +1045,18 @@ int mio_dev_watch (mio_dev_t* dev, mio_dev_watch_cmd_t cmd, int events) break; case MIO_DEV_WATCH_STOP: + if (!(dev->dev_cap & DEV_CAP_ALL_WATCHED)) return 0; /* the device is not being watched */ events = 0; /* override events */ mux_cmd = MIO_SYS_MUX_CMD_DELETE; - break; + dev_cap = dev->dev_cap & ~(DEV_CAP_ALL_WATCHED); + goto ctrl_mux; default: mio_seterrnum (dev->mio, MIO_EINVAL); return -1; } - dev_cap = dev->dev_cap; - dev_cap &= ~(DEV_CAP_ALL_WATCHED); + dev_cap = dev->dev_cap & ~(DEV_CAP_ALL_WATCHED); /* this function honors MIO_DEV_EVENT_IN and MIO_DEV_EVENT_OUT only * as valid input event bits. it intends to provide simple abstraction @@ -1081,6 +1082,7 @@ int mio_dev_watch (mio_dev_t* dev, mio_dev_watch_cmd_t cmd, int events) } else { + ctrl_mux: if (mio_sys_ctrlmux(mio, mux_cmd, dev, dev_cap) <= -1) return -1; } diff --git a/mio/lib/path.c b/mio/lib/path.c index 6796185..dc9b60f 100644 --- a/mio/lib/path.c +++ b/mio/lib/path.c @@ -31,7 +31,7 @@ * support \\?\UNC\server\path which is equivalent to \\server\path. * */ /* ------------------------------------------------------------------ */ -/* WCS IMPLEMENTATION */ +/* UCH IMPLEMENTATION */ /* ------------------------------------------------------------------ */ #if 0 @@ -335,7 +335,7 @@ mio_oow_t mio_canon_ucstr_path (const mio_uch_t* path, mio_uch_t* canon, int fla /* ------------------------------------------------------------------ */ -/* MBS IMPLEMENTATION */ +/* BCH IMPLEMENTATION */ /* ------------------------------------------------------------------ */ #if 0 diff --git a/mio/lib/pro.c b/mio/lib/pro.c index d55cdbe..50abfaa 100644 --- a/mio/lib/pro.c +++ b/mio/lib/pro.c @@ -128,11 +128,12 @@ oops: return -1; } -static pid_t standard_fork_and_exec (mio_t* mio, int pfds[], int flags, param_t* param) +static pid_t standard_fork_and_exec (mio_dev_pro_t* dev, int pfds[], mio_dev_pro_make_t* mi, param_t* param) { + mio_t* mio = dev->mio; pid_t pid; - pid = fork (); + pid = fork(); if (pid == -1) { mio_seterrwithsyserr (mio, 0, errno); @@ -146,8 +147,9 @@ static pid_t standard_fork_and_exec (mio_t* mio, int pfds[], int flags, param_t* mio_syshnd_t devnull = MIO_SYSHND_INVALID; /* TODO: close all uneeded fds */ + if (mi->on_fork) mi->on_fork (dev, mi->fork_ctx); - if (flags & MIO_DEV_PRO_WRITEIN) + if (mi->flags & MIO_DEV_PRO_WRITEIN) { /* slave should read */ close (pfds[1]); @@ -160,7 +162,7 @@ static pid_t standard_fork_and_exec (mio_t* mio, int pfds[], int flags, param_t* pfds[0] = MIO_SYSHND_INVALID; } - if (flags & MIO_DEV_PRO_READOUT) + if (mi->flags & MIO_DEV_PRO_READOUT) { /* slave should write */ close (pfds[2]); @@ -168,7 +170,7 @@ static pid_t standard_fork_and_exec (mio_t* mio, int pfds[], int flags, param_t* if (dup2(pfds[3], 1) == -1) goto slave_oops; - if (flags & MIO_DEV_PRO_ERRTOOUT) + if (mi->flags & MIO_DEV_PRO_ERRTOOUT) { if (dup2(pfds[3], 2) == -1) goto slave_oops; } @@ -177,14 +179,14 @@ static pid_t standard_fork_and_exec (mio_t* mio, int pfds[], int flags, param_t* pfds[3] = MIO_SYSHND_INVALID; } - if (flags & MIO_DEV_PRO_READERR) + if (mi->flags & MIO_DEV_PRO_READERR) { close (pfds[4]); pfds[4] = MIO_SYSHND_INVALID; if (dup2(pfds[5], 2) == -1) goto slave_oops; - if (flags & MIO_DEV_PRO_OUTTOERR) + if (mi->flags & MIO_DEV_PRO_OUTTOERR) { if (dup2(pfds[5], 1) == -1) goto slave_oops; } @@ -193,9 +195,9 @@ static pid_t standard_fork_and_exec (mio_t* mio, int pfds[], int flags, param_t* pfds[5] = MIO_SYSHND_INVALID; } - if ((flags & MIO_DEV_PRO_INTONUL) || - (flags & MIO_DEV_PRO_OUTTONUL) || - (flags & MIO_DEV_PRO_ERRTONUL)) + if ((mi->flags & MIO_DEV_PRO_INTONUL) || + (mi->flags & MIO_DEV_PRO_OUTTONUL) || + (mi->flags & MIO_DEV_PRO_ERRTONUL)) { #if defined(O_LARGEFILE) devnull = open("/dev/null", O_RDWR | O_LARGEFILE, 0); @@ -270,7 +272,7 @@ static int dev_pro_make_master (mio_dev_t* dev, void* ctx) if (make_param(mio, info->cmd, info->flags, ¶m) <= -1) goto oops; /* TODO: more advanced fork and exec .. */ - pid = standard_fork_and_exec(mio, pfds, info->flags, ¶m); + pid = standard_fork_and_exec(dev, pfds, info, ¶m); if (pid <= -1) { free_param (mio, ¶m); @@ -582,6 +584,7 @@ static int dev_pro_write_slave (mio_dev_t* dev, const void* data, mio_iolen_t* l //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 */ { + mio_dev_watch (dev, MIO_DEV_WATCH_STOP, 0); close (pro->pfd); pro->pfd = MIO_SYSHND_INVALID; } @@ -618,6 +621,7 @@ static int dev_pro_writev_slave (mio_dev_t* dev, const mio_iovec_t* iov, mio_iol /*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 */ { + mio_dev_watch (dev, MIO_DEV_WATCH_STOP, 0); close (pro->pfd); pro->pfd = MIO_SYSHND_INVALID; } diff --git a/mio/t/b.sh b/mio/t/b.sh index aba6df0..e284e38 100755 --- a/mio/t/b.sh +++ b/mio/t/b.sh @@ -4,4 +4,6 @@ echo "Content-Type: text/plain" echo "Custom-Attribute: abcdef" echo +printenv exec cat /home/hyung-hwan/projects/hawk/lib/run.c + diff --git a/mio/t/d.sh b/mio/t/d.sh index baaf970..40a62e6 100755 --- a/mio/t/d.sh +++ b/mio/t/d.sh @@ -5,8 +5,8 @@ echo "Content-Type: text/plain" echo -while read x +while IFS= read -r x do - echo $x + echo "$x" done -##echo "<>" +echo "<>" diff --git a/mio/t/e.sh b/mio/t/e.sh new file mode 100755 index 0000000..178cf43 --- /dev/null +++ b/mio/t/e.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +## curl -v --http1.0 --data-binary @/etc/group --http1.1 http://127.0.0.1:9988/home/hyung-hwan/projects/mio/t/d.sh + +echo "Content-Type: text/plain" +echo + +if IFS= read -r x +then + q="${x}" + while IFS= read -r x + do + q="${q} +${x}" + done +else + q = "" +fi + +sleep 3 +printf "%s" "$q" +##echo "<>" diff --git a/mio/t/http1.hawk b/mio/t/http1.hawk index 68adbdc..b2eb608 100644 --- a/mio/t/http1.hawk +++ b/mio/t/http1.hawk @@ -6,7 +6,11 @@ BEGIN { msg = b"GET /home/hyung-hwan/projects/mio/t/b.sh HTTP/1.1\r\n\ Host: www.google.com\r\n\ -Connection: Keep-Alive\r\n\r\n"; +Connection: close\r\n\r\n"; + +#msg = b"GET /home/hyung-hwan/projects/mio/t/b.sh HTTP/1.1\r\n\ +#Host: www.google.com\r\n\ +#Connection: Keep-Alive\r\n\r\n"; sys::write (x, msg);