changed to clear the on_write callbacks for completed write requestrs after having triggered timer callbacks collectively and also before triggering on_read() for each device

cleaned up debugging messages in dns-cli.c
experimenting with http server implementation
This commit is contained in:
hyung-hwan 2020-05-15 06:18:49 +00:00
parent cc74d317a2
commit 57ca185651
9 changed files with 522 additions and 277 deletions

View File

@ -924,7 +924,7 @@ int main (int argc, char* argv[])
setup_arp_tester(mio);
setup_ping4_tester(mio);
#if 1
#if 0
for (i = 0; i < 5; i++)
{
mio_dev_pro_t* pro;
@ -978,6 +978,7 @@ for (i = 0; i < 5; i++)
dnc = mio_svc_dnc_start(mio, &servaddr, MIO_NULL, &send_tmout, &reply_tmout, 2); /* option - send to all, send one by one */
htts = mio_svc_htts_start(mio, &htts_bind_addr);
mio_svc_htts_setservernamewithbcstr (htts, "MIO-HTTP");
#if 1
{
mio_dns_bqr_t qrs[] =

View File

@ -150,7 +150,7 @@ static void release_dns_msg (mio_svc_dnc_t* dnc, mio_dns_msg_t* msg)
mio_t* mio = dnc->mio;
dnc_dns_msg_xtn_t* msgxtn = dnc_dns_msg_getxtn(msg);
MIO_DEBUG1 (mio, "releasing dns msg %d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
MIO_DEBUG1 (mio, "DNC - releasing dns message - msgid:%d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
if (msg == dnc->pending_req || msgxtn->next || msgxtn->prev)
{
@ -179,13 +179,13 @@ static int handle_tcp_packet (mio_dev_sck_t* dev, mio_dns_pkt_t* pkt, mio_uint16
if (!pkt->qr)
{
MIO_DEBUG0 (mio, "dropping dns request received over tcp ...\n"); /* TODO: add source info */
MIO_DEBUG0 (mio, "DNC - dropping dns request received over tcp ...\n"); /* TODO: add source info */
return 0; /* drop request. nothing to do */
}
id = mio_ntoh16(pkt->id);
MIO_DEBUG1 (mio, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<GOT DATA>>>>>>>>>>>id [%d] >>>>>>>>>>>>>>>>>>\n", id);
MIO_DEBUG1 (mio, "DNC - got dns response over tcp - msgid:%d\n", id);
reqmsg = dnc->pending_req;
while (reqmsg)
@ -203,7 +203,7 @@ MIO_DEBUG1 (mio, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<GOT DATA>>>>>>>>>>>id [%d] >>>>
reqmsg = reqmsgxtn->next;
}
MIO_DEBUG1 (mio, "unknown dns response over tcp... %d\n", pkt->id); /* TODO: add source info */
MIO_DEBUG1 (mio, "DNC - unknown dns response over tcp... msgid:%d\n", id); /* TODO: add source info */
return 0;
}
@ -240,12 +240,12 @@ static int on_tcp_read (mio_dev_sck_t* dev, const void* data, mio_iolen_t dlen,
if (MIO_UNLIKELY(dlen <= -1))
{
MIO_DEBUG1 (mio, "dns tcp read error ....%js\n", mio_geterrmsg(mio)); /* TODO: add source packet */
MIO_DEBUG1 (mio, "DNC - dns tcp read error ....%js\n", mio_geterrmsg(mio)); /* TODO: add source packet */
goto oops;
}
else if (MIO_UNLIKELY(dlen == 0))
{
MIO_DEBUG0 (mio, "dns tcp read error ...premature socket hangul\n"); /* TODO: add source packet */
MIO_DEBUG0 (mio, "DNC - dns tcp read error ...premature tcp socket end\n"); /* TODO: add source packet */
goto oops;
}
@ -311,7 +311,7 @@ static void on_tcp_reply_timeout (mio_t* mio, const mio_ntime_t* now, mio_tmrjob
MIO_ASSERT (mio, reqmsgxtn->rtmridx == MIO_TMRIDX_INVALID);
MIO_ASSERT (mio, dev == dnc->tcp_sck);
MIO_DEBUG0 (mio, "*** TIMEOUT ==> unable to receive dns response in time over TCP...\n");
MIO_DEBUG1 (mio, "DNC - unable to receive dns response in time over TCP - msgid:%d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(reqmsg)->id));
if (MIO_LIKELY(reqmsgxtn->on_done)) reqmsgxtn->on_done (dnc, reqmsg, MIO_ETMOUT, MIO_NULL, 0);
release_dns_msg (dnc, reqmsg);
@ -336,6 +336,8 @@ static int on_tcp_write (mio_dev_sck_t* dev, mio_iolen_t wrlen, void* wrctx, con
/* question. schedule to wait for response */
mio_tmrjob_t tmrjob;
MIO_DEBUG1 (mio, "DNC - sent dns question over tcp - msgid:%d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
MIO_MEMSET (&tmrjob, 0, MIO_SIZEOF(tmrjob));
tmrjob.ctx = msg;
mio_gettime (mio, &tmrjob.when);
@ -347,7 +349,7 @@ static int on_tcp_write (mio_dev_sck_t* dev, mio_iolen_t wrlen, void* wrctx, con
{
/* call the callback to indicate this operation failure in the middle of transaction */
status = mio_geterrnum(mio);
MIO_DEBUG0 (mio, "unable to schedule tcp timeout...\n");
MIO_DEBUG1 (mio, "DNC - unable to schedule tcp timeout - msgid: %d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
goto finalize;
}
@ -356,6 +358,7 @@ static int on_tcp_write (mio_dev_sck_t* dev, mio_iolen_t wrlen, void* wrctx, con
else
{
/* no error. successfuly sent a message. no reply is expected */
MIO_DEBUG1 (mio, "DNC - sent dns message over tcp - msgid:%d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
status = MIO_ENOERR;
goto finalize;
}
@ -375,6 +378,8 @@ static int write_dns_msg_over_tcp (mio_dev_sck_t* dev, mio_dns_msg_t* msg)
mio_uint16_t pktlen;
mio_iovec_t iov[2];
MIO_DEBUG1 (mio, "DNC - sending dns message over tcp - msgid:%d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
pktlen = mio_hton16(msg->pktlen);
MIO_ASSERT (mio, msgxtn->rtries == 0);
@ -426,11 +431,11 @@ static void on_tcp_disconnect (mio_dev_sck_t* dev)
if (status == MIO_ENOERR)
{
MIO_DEBUG0 (mio, "TCP DISCONNECTED\n");
MIO_DEBUG0 (mio, "DNC - TCP DISCONNECTED\n");
}
else
{
MIO_DEBUG2 (mio, "TCP UNABLED TO CONNECT %d -> %js\n", status, mio_errnum_to_errstr(status));
MIO_DEBUG2 (mio, "DNC - TCP UNABLE TO CONNECT %d -> %js\n", status, mio_errnum_to_errstr(status));
}
reqmsg = dnc->pending_req;
@ -509,7 +514,7 @@ static int switch_reqmsg_transport_to_tcp (mio_svc_dnc_t* dnc, mio_dns_msg_t* re
reqmsgxtn->rtries = 0;
if (!reqmsgxtn->pending && mio_dns_msg_to_pkt(reqmsg)->qr == 0) chain_pending_dns_reqmsg (dnc, reqmsg);
printf ("SWITCHED >>>>>>>>>>>>>>>>> %p %p %p %p %p\n", reqmsg, reqmsgxtn, reqmsgxtn->dev, dnc->udp_sck, dnc->tcp_sck);
MIO_DEBUG6 (mio, "DNC - switched transport to tcp - msgid:%d %p %p %p %p %p\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(reqmsg)->id), reqmsg, reqmsgxtn, reqmsgxtn->dev, dnc->udp_sck, dnc->tcp_sck);
if (MIO_DEV_SCK_GET_PROGRESS(dnc->tcp_sck) & MIO_DEV_SCK_CONNECTED)
{
@ -536,19 +541,19 @@ static int on_udp_read (mio_dev_sck_t* dev, const void* data, mio_iolen_t dlen,
if (MIO_UNLIKELY(dlen <= -1))
{
MIO_DEBUG1 (mio, "dns read error ....%js\n", mio_geterrmsg(mio)); /* TODO: add source packet */
MIO_DEBUG1 (mio, "DNC - dns read error ....%js\n", mio_geterrmsg(mio)); /* TODO: add source packet */
return 0;
}
if (MIO_UNLIKELY(dlen < MIO_SIZEOF(*pkt)))
{
MIO_DEBUG0 (mio, "dns packet too small from ....\n"); /* TODO: add source packet */
MIO_DEBUG0 (mio, "DNC - dns packet too small from ....\n"); /* TODO: add source packet */
return 0; /* drop */
}
pkt = (mio_dns_pkt_t*)data;
if (!pkt->qr)
{
MIO_DEBUG0 (mio, "dropping dns request received ...\n"); /* TODO: add source info */
MIO_DEBUG0 (mio, "DNC - dropping dns request received ...\n"); /* TODO: add source info */
return 0; /* drop request */
}
@ -583,7 +588,7 @@ static int on_udp_read (mio_dev_sck_t* dev, const void* data, mio_iolen_t dlen,
/* TODO: add an option to call an error callback with TRUNCATION error code instead of fallback to received UDP truncated message */
}
MIO_DEBUG1 (mio, "received dns response over udp..id %d\n", id);
MIO_DEBUG1 (mio, "DNC - received dns response over udp for msgid:%d\n", id);
if (MIO_LIKELY(reqmsgxtn->on_done)) reqmsgxtn->on_done (dnc, reqmsg, MIO_ENOERR, data, dlen);
release_dns_msg (dnc, reqmsg);
return 0;
@ -593,7 +598,7 @@ MIO_DEBUG1 (mio, "received dns response over udp..id %d\n", id);
}
/* the response id didn't match the ID of pending requests - need to wait longer? */
MIO_DEBUG1 (mio, "unknown dns response... %d\n", pkt->id); /* TODO: add source info */
MIO_DEBUG1 (mio, "DNC - unknown dns response over udp... msgid:%d\n", id); /* TODO: add source info */
return 0;
}
@ -608,12 +613,13 @@ static void on_udp_reply_timeout (mio_t* mio, const mio_ntime_t* now, mio_tmrjob
MIO_ASSERT (mio, msgxtn->rtmridx == MIO_TMRIDX_INVALID);
MIO_ASSERT (mio, dev == dnc->udp_sck);
MIO_DEBUG0 (mio, "*** TIMEOUT ==> unable to receive dns response in time...\n");
MIO_DEBUG1 (mio, "DNC - unable to receive dns response in time over udp - msgid:%d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(reqmsg)->id));
if (msgxtn->rtries < msgxtn->rmaxtries)
{
mio_ntime_t* tmout;
tmout = MIO_IS_POS_NTIME(&msgxtn->wtmout)? &msgxtn->wtmout: MIO_NULL;
MIO_DEBUG1 (mio, "DNC - sending dns question again over udp - msgid:%d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(reqmsg)->id));
if (mio_dev_sck_timedwrite(dev, mio_dns_msg_to_pkt(reqmsg), reqmsg->pktlen, tmout, reqmsg, &msgxtn->servaddr) >= 0) return; /* resent */
/* retry failed */
@ -624,7 +630,6 @@ MIO_DEBUG0 (mio, "*** TIMEOUT ==> unable to receive dns response in time...\n");
release_dns_msg (dnc, reqmsg);
}
static int on_udp_write (mio_dev_sck_t* dev, mio_iolen_t wrlen, void* wrctx, const mio_skad_t* dstaddr)
{
mio_t* mio = dev->mio;
@ -646,7 +651,7 @@ static int on_udp_write (mio_dev_sck_t* dev, mio_iolen_t wrlen, void* wrctx, con
/* question. schedule to wait for response */
mio_tmrjob_t tmrjob;
MIO_DEBUG1 (mio, "sent dns question %d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
MIO_DEBUG1 (mio, "DNC - sent dns question over udp - msgid:%d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
MIO_MEMSET (&tmrjob, 0, MIO_SIZEOF(tmrjob));
tmrjob.ctx = msg;
mio_gettime (mio, &tmrjob.when);
@ -658,10 +663,10 @@ MIO_DEBUG1 (mio, "sent dns question %d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(ms
{
/* call the callback to indicate this operation failure in the middle of transaction */
status = mio_geterrnum(mio);
MIO_DEBUG0 (mio, "unable to schedule timeout...\n");
MIO_DEBUG1 (mio, "DNC - unable to schedule udp timeout - msgid:%d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
goto finalize;
}
if (msgxtn->rtries == 0)
{
/* this is the first wait */
@ -673,7 +678,7 @@ MIO_DEBUG1 (mio, "sent dns question %d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(ms
}
else
{
MIO_DEBUG1 (mio, "sent dns message %d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
MIO_DEBUG1 (mio, "DNC - sent dns message over udp - msgid:%d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
/* sent an answer. however this may be a question if msgxtn->rmaxtries is 0. */
status = MIO_ENOERR;
goto finalize;
@ -693,7 +698,7 @@ static void on_udp_connect (mio_dev_sck_t* dev)
static void on_udp_disconnect (mio_dev_sck_t* dev)
{
mio_t* mio = dev->mio;
/*mio_t* mio = dev->mio;*/
mio_svc_dnc_t* dnc = ((dnc_sck_xtn_t*)mio_dev_sck_getxtn(dev))->dnc;
mio_dns_msg_t* reqmsg;
@ -763,6 +768,7 @@ mio_svc_dnc_t* mio_svc_dnc_start (mio_t* mio, const mio_skad_t* serv_addr, const
}
MIO_SVCL_APPEND_SVC (&mio->actsvc, (mio_svc_t*)dnc);
MIO_DEBUG1 (mio, "DNC - STARTED SERVICE %p\n", dnc);
return dnc;
oops:
@ -778,6 +784,7 @@ void mio_svc_dnc_stop (mio_svc_dnc_t* dnc)
{
mio_t* mio = dnc->mio;
MIO_DEBUG1 (mio, "DNC - STOPPING SERVICE %p\n", dnc);
if (dnc->udp_sck) mio_dev_sck_kill (dnc->udp_sck);
if (dnc->tcp_sck) mio_dev_sck_kill (dnc->tcp_sck);
while (dnc->pending_req) release_dns_msg (dnc, dnc->pending_req);
@ -793,6 +800,8 @@ static MIO_INLINE int send_dns_msg (mio_svc_dnc_t* dnc, mio_dns_msg_t* msg, int
if ((send_flags & MIO_SVC_DNC_SEND_FLAG_PREFER_TCP) && switch_reqmsg_transport_to_tcp(dnc, msg) >= 0) return 0;
MIO_DEBUG1 (dnc->mio, "DNC - sending dns message over udp - msgid:%d\n", (int)mio_ntoh16(mio_dns_msg_to_pkt(msg)->id));
tmout = MIO_IS_POS_NTIME(&msgxtn->wtmout)? &msgxtn->wtmout: MIO_NULL;
/* TODO: optionally, override dnc->serv_addr and use the target address passed as a parameter */
return mio_dev_sck_timedwrite(dnc->udp_sck, mio_dns_msg_to_pkt(msg), msg->pktlen, tmout, msg, &msgxtn->servaddr);

View File

@ -728,7 +728,7 @@ static mio_htb_pair_t* hdr_cbserter (
}
else
{
if (capture_key_header (tx->htrd, p) <= -1)
if (capture_key_header(tx->htrd, p) <= -1)
{
/* Destroy the pair created here
* as it is not added to the hash table yet */
@ -793,7 +793,7 @@ static mio_htb_pair_t* hdr_cbserter (
/* append it to the list*/
tmp->next = val;
if (capture_key_header (tx->htrd, pair) <= -1) return MIO_NULL;
if (capture_key_header(tx->htrd, pair) <= -1) return MIO_NULL;
return pair;
}
}
@ -1102,7 +1102,7 @@ done:
}
/* feed the percent encoded string */
int mio_htrd_feed (mio_htrd_t* htrd, const mio_bch_t* req, mio_oow_t len)
int mio_htrd_feed (mio_htrd_t* htrd, const mio_bch_t* req, mio_oow_t len, mio_oow_t* rem)
{
const mio_bch_t* end = req + len;
const mio_bch_t* ptr = req;
@ -1122,7 +1122,7 @@ int mio_htrd_feed (mio_htrd_t* htrd, const mio_bch_t* req, mio_oow_t len)
{
/* treat everything as contents.
* i don't care about headers or whatsoever. */
return push_content (htrd, req, len);
return push_content(htrd, req, len);
}
/* does this goto drop code maintainability? */
@ -1199,7 +1199,7 @@ int mio_htrd_feed (mio_htrd_t* htrd, const mio_bch_t* req, mio_oow_t len)
/* we got a complete request header. */
MIO_ASSERT (htrd->mio, htrd->fed.s.crlf <= 3);
/* reset the crlf state */
htrd->fed.s.crlf = 0;
/* reset the raw request length */
@ -1228,7 +1228,7 @@ int mio_htrd_feed (mio_htrd_t* htrd, const mio_bch_t* req, mio_oow_t len)
* reading CGI outputs. So it comes with
* awkwardity described above.
*/
if (ptr < end && push_content (htrd, ptr, end - ptr) <= -1) return -1;
if (ptr < end && push_content(htrd, ptr, end - ptr) <= -1) return -1;
/* i don't really know if it is really completed
* with content. MIO_HTRD_PEEKONLY is not compatible
@ -1246,7 +1246,7 @@ int mio_htrd_feed (mio_htrd_t* htrd, const mio_bch_t* req, mio_oow_t len)
if (htrd->re.flags & MIO_HTRE_ATTR_CHUNKED)
{
/* transfer-encoding: chunked */
MIO_ASSERT (htrd->mio, !(htrd->re.flags & MIO_HTRE_ATTR_LENGTH));
/*MIO_ASSERT (htrd->mio, !(htrd->re.flags & MIO_HTRE_ATTR_LENGTH)); <- this assertion is wrong. non-conforming client may include content-length while transfer-encoding is chunked*/
dechunk_start:
htrd->fed.s.chunk.phase = GET_CHUNK_LEN;
@ -1254,8 +1254,8 @@ int mio_htrd_feed (mio_htrd_t* htrd, const mio_bch_t* req, mio_oow_t len)
htrd->fed.s.chunk.count = 0;
dechunk_resume:
ptr = getchunklen (htrd, ptr, end - ptr);
if (ptr == MIO_NULL) return -1;
ptr = getchunklen(htrd, ptr, end - ptr);
if (MIO_UNLIKELY(!ptr)) return -1;
if (htrd->fed.s.chunk.phase == GET_CHUNK_LEN)
{
@ -1274,8 +1274,8 @@ int mio_htrd_feed (mio_htrd_t* htrd, const mio_bch_t* req, mio_oow_t len)
htrd->fed.s.crlf = 2;
dechunk_get_trailers:
ptr = get_trailing_headers (htrd, ptr, end);
if (ptr == MIO_NULL) return -1;
ptr = get_trailing_headers(htrd, ptr, end);
if (!MIO_UNLIKELY(ptr)) return -1;
if (htrd->fed.s.chunk.phase == GET_CHUNK_TRAILERS)
{
@ -1450,12 +1450,12 @@ XXXXXXXX
* plus complete content body and the header
* of the next request. */
int n;
htrd->errnum = MIO_HTRD_ENOERR;
htrd->errnum = MIO_HTRD_ENOERR;
n = htrd->recbs->peek(htrd, &htrd->re);
if (n <= -1)
{
if (htrd->errnum == MIO_HTRD_ENOERR)
htrd->errnum = MIO_HTRD_ERECBS;
htrd->errnum = MIO_HTRD_ERECBS;
/* need to clear request on error?
clear_feed (htrd); */
return -1;
@ -1472,7 +1472,7 @@ XXXXXXXX
if (n <= -1)
{
if (htrd->errnum == MIO_HTRD_ENOERR)
htrd->errnum = MIO_HTRD_ERECBS;
htrd->errnum = MIO_HTRD_ERECBS;
/* need to clear request on error?
clear_feed (htrd); */
return -1;
@ -1484,28 +1484,37 @@ mio_printf (MIO_T("CONTENT_LENGTH %d, RAW HEADER LENGTH %d\n"),
(int)MIO_BECS_LEN(&htrd->re.content),
(int)MIO_BECS_LEN(&htrd->fed.b.raw));
#endif
clear_feed (htrd);
if (ptr >= end) return 0; /* no more feeds to handle */
if (htrd->flags & FEEDING_SUSPENDED)
if (rem)
{
/* stop even if there are fed data left */
*rem = end - ptr; /* remaining feeds */
return 0; /* to indicate completed when the 'rem' is not NULL */
}
else if (ptr >= end)
{
/* no more feeds to handle */
return 0;
}
if (htrd->flags & FEEDING_SUSPENDED) /* in case the callback called mio_htrd_suspend() */
{
htrd->errnum = MIO_HTRD_ESUSPENDED;
return -1;
}
/*if (htrd->option & MIO_HTRD_DUMMY)*/
if (htrd->flags & FEEDING_DUMMIFIED)
if (htrd->flags & FEEDING_DUMMIFIED) /* in case the callback called mio_htrd_dummify() */
{
/* once the mode changes to RAW in a callback,
* left-over is pushed as contents */
if (ptr < end)
return push_content (htrd, ptr, end - ptr);
return push_content(htrd, ptr, end - ptr);
else
return 0;
}
/* let ptr point to the next character to LF or
* the optional contents */
req = ptr;
@ -1537,31 +1546,32 @@ mio_printf (MIO_T("CONTENT_LENGTH %d, RAW HEADER LENGTH %d\n"),
if (ptr > req)
{
/* enbuffer the incomplete request */
if (push_to_buffer (htrd, &htrd->fed.b.raw, req, ptr - req) <= -1) return -1;
if (push_to_buffer(htrd, &htrd->fed.b.raw, req, ptr - req) <= -1) return -1;
}
feedme_more:
if (header_completed_during_this_feed && htrd->recbs->peek)
{
int n;
htrd->errnum = MIO_HTRD_ENOERR;
n = htrd->recbs->peek (htrd, &htrd->re);
htrd->errnum = MIO_HTRD_ENOERR;
n = htrd->recbs->peek(htrd, &htrd->re);
if (n <= -1)
{
if (htrd->errnum == MIO_HTRD_ENOERR)
htrd->errnum = MIO_HTRD_ERECBS;
htrd->errnum = MIO_HTRD_ERECBS;
/* need to clear request on error?
clear_feed (htrd); */
return -1;
}
}
if (rem) *rem = 0;
return 0;
}
int mio_htrd_halt (mio_htrd_t* htrd)
{
if (htrd->fed.s.flags & CONSUME_UNTIL_CLOSE || !htrd->clean)
if ((htrd->fed.s.flags & CONSUME_UNTIL_CLOSE) || !htrd->clean)
{
mio_htre_completecontent (&htrd->re);
@ -1573,7 +1583,7 @@ int mio_htrd_halt (mio_htrd_t* htrd)
if (n <= -1)
{
if (htrd->errnum == MIO_HTRD_ENOERR)
htrd->errnum = MIO_HTRD_ERECBS;
htrd->errnum = MIO_HTRD_ERECBS;
/* need to clear request on error?
clear_feed (htrd); */
return -1;
@ -1657,7 +1667,7 @@ int mio_htrd_scanqparam (mio_htrd_t* htrd, const mio_bcs_t* cstr)
MIO_ASSERT (htrd->mio, htrd->recbs->qparamstr != MIO_NULL);
htrd->errnum = MIO_HTRD_ENOERR;
if (htrd->recbs->qparamstr (htrd, &key, &val) <= -1)
if (htrd->recbs->qparamstr(htrd, &key, &val) <= -1)
{
if (htrd->errnum == MIO_HTRD_ENOERR)
htrd->errnum = MIO_HTRD_ERECBS;

View File

@ -172,7 +172,6 @@ if (mio_htre_getcontentlen(req) > 0)
* i don't want to delay this until the contents are received.
* if you don't like this behavior, you must implement your own
* callback function for request handling. */
#if 0
/* TODO support X-HTTP-Method-Override */
if (data.method == MIO_HTTP_POST)
@ -197,36 +196,22 @@ if (mio_htre_getcontentlen(req) > 0)
}
else
{
//mio_svc_htts_sendstatus (htts, csck, 500, mth, mio_htre_getversion(req), (req->flags & MIO_HTRE_ATTR_KEEPALIVE), MIO_NULL);
//return 0;
if (mth == MIO_HTTP_POST &&
!(req->flags & MIO_HTRE_ATTR_LENGTH) &&
!(req->flags & MIO_HTRE_ATTR_CHUNKED))
if (mth == MIO_HTTP_POST && !(req->flags & (MIO_HTRE_ATTR_LENGTH | MIO_HTRE_ATTR_CHUNKED)))
{
/* POST without Content-Length nor not chunked */
req->flags &= ~MIO_HTRE_ATTR_KEEPALIVE;
mio_htre_discardcontent (req);
mio_htre_discardcontent (req);
/* 411 Length Required - can't keep alive. Force disconnect */
mio_svc_htts_sendstatus (htts, csck, 411, mth, mio_htre_getversion(req), 0, MIO_NULL); /* TODO: error check... */
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 */
}
else
{
/* TODO: handle 100 continue??? */
if ((req->flags & MIO_HTRE_ATTR_EXPECT) &&
mio_comp_http_version_numbers(&req->version, 1, 1) >= 0 &&
mio_htre_getcontentlen(req) <= 0)
{
if (req->flags & MIO_HTRE_ATTR_EXPECT100)
{
mio_dev_sck_write(csck, "HTTP/1.1 100 Continue\r\n", 23, MIO_NULL, MIO_NULL);
}
else
{
}
}
const mio_bch_t* qpath = mio_htre_getqpath(req);
if (mio_svc_htts_docgi(htts, csck, req, "") <= -1)
{
mio_dev_sck_halt (csck);
}
#if 0
/*
if (mio_comp_bcstr(qpath, "/testfunc", 0) == 0)
{
@ -241,54 +226,8 @@ if (mio_htre_getcontentlen(req) > 0)
mio_htre_discardcontent (req);
mio_dev_sck_halt (csck);
}
/*
if (mio_comp_bcstr(qpath, "/mio.c", 0) == 0)
{
mio_svc_htts_sendfile (htts, csck, "/home/hyung-hwan/projects/mio/lib/mio.c", 200, mth, mio_htre_getversion(req), (req->flags & MIO_HTRE_ATTR_KEEPALIVE));
}
else
{
mio_svc_htts_sendstatus (htts, csck, 500, mth, mio_htre_getversion(req), (req->flags & MIO_HTRE_ATTR_KEEPALIVE), MIO_NULL);
}*/
}
#if 0
else if (server_xtn->makersrc(htts, client, req, &rsrc) <= -1)
{
/* failed to make a resource. just send the internal server error.
* the makersrc handler can return a negative number to return
* '500 Internal Server Error'. If it wants to return a specific
* error code, it should return 0 with the MIO_HTTPD_RSRC_ERROR
* resource. */
mio_htts_discardcontent (req);
task = mio_htts_entaskerror(htts, client, MIO_NULL, 500, req);
}
else
{
task = MIO_NULL;
if ((rsrc.flags & MIO_HTTPD_RSRC_100_CONTINUE) &&
(task = mio_htts_entaskcontinue(htts, client, task, req)) == MIO_NULL)
{
/* inject '100 continue' first if it is needed */
goto oops;
}
/* arrange the actual resource to be returned */
task = mio_htts_entaskrsrc(htts, client, task, &rsrc, req);
server_xtn->freersrc (htts, client, req, &rsrc);
/* if the resource is indicating to return an error,
* discard the contents since i won't return them */
if (rsrc.type == MIO_HTTPD_RSRC_ERROR)
{
mio_htre_discardcontent (req);
}
}
if (task == MIO_NULL) goto oops;
#endif
}
}
}
else
@ -296,38 +235,14 @@ if (mio_htre_getcontentlen(req) > 0)
/* contents are all received */
if (mth == MIO_HTTP_CONNECT)
{
MIO_DEBUG1 (htts->mio, "Switching HTRD to DUMMY for [%hs]\n", mio_htre_getqpath(req));
/* Switch the http reader to a dummy mode so that the subsqeuent
* input(request) is just treated as data to the request just
* completed */
mio_htrd_dummify (cli->htrd);
/* connect is not handled in the peek mode. create a proxy resource here */
////////
#if 0
if (server_xtn->makersrc(htts, client, req, &rsrc) <= -1)
{
MIO_DEBUG1 (htts->mio, "Cannot make resource for [%hs]\n", mio_htre_getqpath(req));
/* failed to make a resource. just send the internal server error.
* the makersrc handler can return a negative number to return
* '500 Internal Server Error'. If it wants to return a specific
* error code, it should return 0 with the MIO_HTTPD_RSRC_ERROR
* resource. */
task = mio_htts_entaskerror(htts, client, MIO_NULL, 500, req);
}
else
{
/* arrange the actual resource to be returned */
task = mio_htts_entaskrsrc (htts, client, MIO_NULL, &rsrc, req);
server_xtn->freersrc (htts, client, req, &rsrc);
}
if (task == MIO_NULL) goto oops;
#endif
////////
/* TODO: arrange to forward all raw bytes */
}
else if (req->flags & MIO_HTRE_ATTR_PROXIED)
{
@ -446,25 +361,52 @@ static void fini_client (mio_svc_htts_cli_t* cli)
/* ------------------------------------------------------------------------ */
static int client_on_read (mio_dev_sck_t* sck, const void* buf, mio_iolen_t len, const mio_skad_t* srcaddr)
static int listener_on_read (mio_dev_sck_t* sck, const void* buf, mio_iolen_t len, const mio_skad_t* srcaddr)
{
/* unlike the function name, this callback is set on both the listener and the client.
* however, it must never be triggered for the listener */
mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(sck);
printf ("** HTTS - client read %p %d -> htts:%p\n", sck, (int)len, cli->htts);
mio_oow_t rem;
int x;
MIO_ASSERT (sck->mio, sck != cli->htts->lsck);
printf ("** HTTS - client read socket(%p) %d -> htts:%p\n", sck, (int)len, cli->htts);
{
mio_iolen_t i;
for (i = 0; i < len; i++)
{
printf ("%c", ((const mio_uint8_t*)buf)[i]);
}
}
if (len <= 0)
{
mio_dev_sck_halt (sck);
}
else if (mio_htrd_feed(cli->htrd, buf, len) <= -1)
else 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 ... */
mio_dev_sck_halt (sck);
}
else if (rem > 0)
{
/* TODO: store the remaining data in the client's buffer */
}
return 0;
}
static int client_on_write (mio_dev_sck_t* sck, mio_iolen_t wrlen, void* wrctx, const mio_skad_t* dstaddr)
static int listener_on_write (mio_dev_sck_t* sck, mio_iolen_t wrlen, void* wrctx, const mio_skad_t* dstaddr)
{
mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(sck);
mio_svc_htts_rsrc_t* rsrc = (mio_svc_htts_rsrc_t*)wrctx;
MIO_ASSERT (sck->mio, sck != cli->htts->lsck);
if (rsrc)
{
int n;
@ -479,18 +421,7 @@ static int client_on_write (mio_dev_sck_t* sck, mio_iolen_t wrlen, void* wrctx,
}
return 0;
}
/* ------------------------------------------------------------------------ */
static int listener_on_read (mio_dev_sck_t* sck, const void* buf, mio_iolen_t len, const mio_skad_t* srcaddr)
{
return 0;
}
static int listener_on_write (mio_dev_sck_t* sck, mio_iolen_t wrlen, void* wrctx, const mio_skad_t* dstaddr)
{
return 0;
}
static void listener_on_connect (mio_dev_sck_t* sck)
@ -502,13 +433,9 @@ static void listener_on_connect (mio_dev_sck_t* sck)
/* accepted a new client */
MIO_DEBUG3 (sck->mio, "HTTS(%p) - accepted... %p %d \n", cli->htts, sck, sck->hnd);
/* the accepted socket inherits various event callbacks. switch some of them to avoid sharing */
sck->on_read = client_on_read;
sck->on_write = client_on_write;
if (init_client(cli, sck) <= -1)
{
MIO_INFO2 (sck->mio, "UNABLE TO INITIALIZE NEW CLIENT %p %d\n", sck, (int)sck->hnd);
MIO_DEBUG2 (sck->mio, "UNABLE TO INITIALIZE NEW CLIENT %p %d\n", sck, (int)sck->hnd);
mio_dev_sck_halt (sck);
}
}
@ -529,21 +456,21 @@ static void listener_on_disconnect (mio_dev_sck_t* sck)
{
case MIO_DEV_SCK_CONNECTING:
/* only for connecting sockets */
MIO_INFO1 (sck->mio, "OUTGOING SESSION DISCONNECTED - FAILED TO CONNECT (%d) TO REMOTE SERVER\n", (int)sck->hnd);
MIO_DEBUG1 (sck->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_INFO1 (sck->mio, "OUTGOING SESSION DISCONNECTED - FAILED TO SSL-CONNECT (%d) TO REMOTE SERVER\n", (int)sck->hnd);
MIO_DEBUG1 (sck->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_INFO1 (sck->mio, "OUTGOING CLIENT CONNECTION GOT TORN DOWN %p(%d).......\n", (int)sck->hnd);
MIO_DEBUG1 (sck->mio, "OUTGOING CLIENT CONNECTION GOT TORN DOWN %p(%d).......\n", (int)sck->hnd);
break;
case MIO_DEV_SCK_LISTENING:
MIO_INFO2 (sck->mio, "LISTNER SOCKET %p(%d) - SHUTTUING DOWN\n", sck, (int)sck->hnd);
MIO_DEBUG2 (sck->mio, "LISTNER SOCKET %p(%d) - SHUTTUING DOWN\n", sck, (int)sck->hnd);
break;
case MIO_DEV_SCK_ACCEPTING_SSL: /* special case. */
@ -552,17 +479,17 @@ static void listener_on_disconnect (mio_dev_sck_t* sck)
* 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_INFO2 (sck->mio, "LISTENER UNABLE TO SSL-ACCEPT CLIENT %p(%d) ....%p\n", sck, (int)sck->hnd);
MIO_DEBUG2 (sck->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_INFO2 (sck->mio, "ACCEPTED CLIENT SOCKET %p(%d) GOT DISCONNECTED.......\n", sck, (int)sck->hnd);
MIO_DEBUG2 (sck->mio, "ACCEPTED CLIENT SOCKET %p(%d) GOT DISCONNECTED.......\n", sck, (int)sck->hnd);
break;
default:
MIO_INFO2 (sck->mio, "SOCKET %p(%d) DISCONNECTED AFTER ALL.......\n", sck, (int)sck->hnd);
MIO_DEBUG2 (sck->mio, "SOCKET %p(%d) DISCONNECTED AFTER ALL.......\n", sck, (int)sck->hnd);
break;
}
@ -639,7 +566,7 @@ mio_svc_htts_t* mio_svc_htts_start (mio_t* mio, const mio_skad_t* bind_addr)
MIO_MEMSET (&info, 0, MIO_SIZEOF(info));
info.b.localaddr = *bind_addr;
info.b.options = MIO_DEV_SCK_BIND_REUSEADDR | MIO_DEV_SCK_BIND_REUSEPORT;
info.b.options |= MIO_DEV_SCK_BIND_SSL;
/*info.b.options |= MIO_DEV_SCK_BIND_SSL; */
info.b.ssl_certfile = "localhost.crt";
info.b.ssl_keyfile = "localhost.key";
if (mio_dev_sck_bind(htts->lsck, &info.b) <= -1) goto oops;
@ -657,7 +584,7 @@ mio_svc_htts_t* mio_svc_htts_start (mio_t* mio, const mio_skad_t* bind_addr)
MIO_SVCL_APPEND_SVC (&mio->actsvc, (mio_svc_t*)htts);
CLIL_INIT (&htts->cli);
MIO_DEBUG3 (mio, "STARTED SVC(HTTS) LISTENER %p LISTENER SOCKET %p(%d)\n", htts, htts->lsck, (int)htts->lsck->hnd);
MIO_DEBUG3 (mio, "HTTS - STARTED SERVICE %p - LISTENER SOCKET %p(%d)\n", htts, htts->lsck, (int)htts->lsck->hnd);
return htts;
oops:
@ -673,7 +600,7 @@ void mio_svc_htts_stop (mio_svc_htts_t* htts)
{
mio_t* mio = htts->mio;
MIO_DEBUG3 (mio, "STOPPING SVC(HTTS) %p LISTENER SOCKET %p(%d)\n", htts, htts->lsck, (int)(htts->lsck? htts->lsck->hnd: -1));
MIO_DEBUG3 (mio, "HTTS - STOPPING SERVICE %p - LISTENER SOCKET %p(%d)\n", htts, htts->lsck, (int)(htts->lsck? htts->lsck->hnd: -1));
/* htts->lsck may be null if the socket has been destroyed for operational error and
* forgotten in the disconnect callback thereafter */
@ -732,7 +659,7 @@ mio_svc_htts_rsrc_t* mio_svc_htts_rsrc_make (mio_svc_htts_t* htts, mio_dev_sck_t
void mio_svc_htts_rsrc_kill (mio_svc_htts_rsrc_t* rsrc)
{
printf ("RSRC KILL >>>>> %p\n", rsrc->htts);
printf ("RSRC KILL >>>>> htts=> %p\n", rsrc->htts);
mio_t* mio = rsrc->htts->mio;
if (rsrc->on_kill) rsrc->on_kill (rsrc);
@ -936,34 +863,99 @@ int mio_svc_htts_dofile (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t*
/* ----------------------------------------------------------------- */
struct cgi_state_t
{
/**** CHANGE THESE FIELDS AFTER RSRC CLEANUP */
mio_svc_htts_t* htts;
mio_svc_htts_rsrc_t* rsrc_prev;
mio_svc_htts_rsrc_t* rsrc_next;
mio_svc_htts_rsrc_on_kill_t on_kill;
/**** CHANGE THESE FIELDS AFTER RSRC CLEANUP */
mio_oow_t num_pending_writes_to_client;
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_htre_t* req;
mio_oow_t req_content_length;
mio_dev_sck_on_read_t cli_org_on_read;
mio_dev_sck_on_write_t cli_org_on_write;
};
typedef struct cgi_state_t cgi_state_t;
struct cgi_peer_xtn_t
{
cgi_state_t* state;
};
typedef struct cgi_peer_xtn_t cgi_peer_xtn_t;
static void cgi_state_on_kill (cgi_state_t* cgi_state)
{
printf ("**** CGI_STATE_ON_KILL \n");
if (cgi_state->peer)
{
mio_dev_pro_kill (cgi_state->peer);
cgi_state->peer = MIO_NULL;
}
if (cgi_state->peer_htrd)
{
mio_htrd_close (cgi_state->peer_htrd);
cgi_state->peer_htrd = MIO_NULL;
}
if (cgi_state->cli_org_on_read)
{
cgi_state->cli->sck->on_read = cgi_state->cli_org_on_read;
cgi_state->cli_org_on_read = MIO_NULL;
}
if (cgi_state->cli_org_on_write)
{
cgi_state->cli->sck->on_write = cgi_state->cli_org_on_write;
cgi_state->cli_org_on_write = MIO_NULL;
}
}
static void cgi_peer_on_close (mio_dev_pro_t* pro, mio_dev_pro_sid_t sid)
{
mio_t* mio = pro->mio;
cgi_peer_xtn_t* cgi_peer = mio_dev_pro_getxtn(pro);
if (sid == MIO_DEV_PRO_MASTER)
MIO_INFO1 (mio, "PROCESS(%d) CLOSE MASTER\n", (int)pro->child_pid);
{
MIO_DEBUG1 (mio, "PROCESS(%d) CLOSE MASTER\n", (int)pro->child_pid);
cgi_peer->state->peer = MIO_NULL; /* clear this peer from the state */
}
else
MIO_INFO2 (mio, "PROCESS(%d) CLOSE SLAVE[%d]\n", (int)pro->child_pid, sid);
{
MIO_DEBUG2 (mio, "PROCESS(%d) CLOSE SLAVE[%d]\n", (int)pro->child_pid, sid);
}
}
static int cgi_peer_on_read (mio_dev_pro_t* pro, mio_dev_pro_sid_t sid, const void* data, mio_iolen_t dlen)
{
mio_t* mio = pro->mio;
cgi_peer_xtn_t* cgi_peer = mio_dev_pro_getxtn(pro);
if (dlen <= -1)
{
MIO_INFO1 (mio, "PROCESS(%d): READ TIMED OUT...\n", (int)pro->child_pid);
MIO_DEBUG1 (mio, "PROCESS(%d): READ TIMED OUT...\n", (int)pro->child_pid);
mio_dev_pro_halt (pro);
return 0;
}
else if (dlen <= 0)
{
MIO_INFO1 (mio, "PROCESS(%d): EOF RECEIVED...\n", (int)pro->child_pid);
MIO_DEBUG1 (mio, "PROCESS(%d): EOF RECEIVED...\n", (int)pro->child_pid);
/* no outstanding request. but EOF */
mio_dev_pro_halt (pro);
return 0;
}
MIO_INFO5 (mio, "PROCESS(%d) READ DATA ON SLAVE[%d] len=%d [%.*hs]\n", (int)pro->child_pid, (int)sid, (int)dlen, dlen, (char*)data);
MIO_DEBUG5 (mio, "PROCESS(%d) READ DATA ON SLAVE[%d] len=%d [%.*hs]\n", (int)pro->child_pid, (int)sid, (int)dlen, dlen, (char*)data);
if (sid == MIO_DEV_PRO_OUT)
{
mio_dev_pro_read (pro, sid, 0);
@ -975,18 +967,34 @@ static int cgi_peer_on_read (mio_dev_pro_t* pro, mio_dev_pro_sid_t sid, const vo
static int cgi_peer_on_write (mio_dev_pro_t* pro, mio_iolen_t wrlen, void* wrctx)
{
mio_t* mio = pro->mio;
cgi_peer_xtn_t* cgi_peer = mio_dev_pro_getxtn(pro);
cgi_state_t* cgi_state = cgi_peer->state;
mio_ntime_t tmout;
if (wrlen <= -1)
{
MIO_INFO1 (mio, "PROCESS(%d): WRITE TIMED OUT...\n", (int)pro->child_pid);
MIO_DEBUG1 (mio, "PROCESS(%d): WRITE TIMED OUT...\n", (int)pro->child_pid);
mio_dev_pro_halt (pro);
return 0;
}
MIO_DEBUG2 (mio, "PROCESS(%d) wrote data of %d bytes\n", (int)pro->child_pid, (int)wrlen);
#if 0
/*mio_dev_pro_read (pro, MIO_DEV_PRO_OUT, 1);*/
MIO_INIT_NTIME (&tmout, 5, 0);
mio_dev_pro_timedread (pro, MIO_DEV_PRO_OUT, 1, &tmout);
#endif
#if 0
if (mio_dev_pro_write(pro, cgi_peer->cli->req, length, MIO_NULL) <= -1)
{
/* halt both peer and cli */
}
#endif
cgi_state->num_pending_writes_to_peer--;
return 0;
}
@ -994,84 +1002,211 @@ static int cgi_peer_on_write (mio_dev_pro_t* pro, mio_iolen_t wrlen, void* wrctx
static int cgi_client_on_read (mio_dev_sck_t* sck, const void* buf, mio_iolen_t len, const mio_skad_t* srcaddr)
{
mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(sck);
cgi_state_t* cgi_state = RSRCL_FIRST_RSRC(&cli->rsrc);
printf ("** HTTS - cgi client read %p %d -> htts:%p\n", sck, (int)len, cli->htts);
if (len <= 0)
if (len <= -1)
{
/* read error */
mio_dev_sck_halt (sck);
goto oops;
}
else if (mio_htrd_feed(cli->htrd, buf, len) <= -1)
else if (len == 0)
{
mio_dev_sck_halt (sck);
/* EOF */
}
else
{
#if 0
mio_oow_t rem;
if (mio_htrd_feed(cli->htrd, buf, len, &rem) <= -1) goto oops;
if (rem > 0)
{
/* TODO: there is left-over data */
}
#endif
cgi_state->num_pending_writes_to_peer++;
if (mio_dev_pro_write(cgi_state->peer, buf, len, MIO_NULL) <= -1)
{
cgi_state->num_pending_writes_to_peer--;
goto oops;
}
if (cgi_state->num_pending_writes_to_peer > 1)
{
if (mio_dev_sck_read(sck, 0) <= -1) goto oops; /* disable input watching */
}
}
return 0;
oops:
/* TODO: arrange to kill the entire cgi_state??? */
mio_dev_sck_halt (sck);
return 0;
}
static int cgi_client_on_write (mio_dev_sck_t* sck, mio_iolen_t wrlen, void* wrctx, const mio_skad_t* dstaddr)
{
mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(sck);
cgi_state_t* cgi_state = RSRCL_FIRST_RSRC(&cli->rsrc);
return 0;
}
static void cgi_client_on_disconnect (mio_dev_sck_t* sck)
static int get_request_content_length (mio_htre_t* req, mio_oow_t* len)
{
client_on_disconnect (sck);
}
if (req->state & (MIO_HTRE_COMPLETED | MIO_HTRE_DISCARDED))
{
/* no more content to receive */
*len = mio_htre_getcontentlen(req);
}
else if (req->flags & MIO_HTRE_ATTR_CHUNKED)
{
/* "Transfer-Encoding: chunked" take precedence over "Content-Length: XXX".
*
* [RFC7230]
* If a message is received with both a Transfer-Encoding and a
* Content-Length header field, the Transfer-Encoding overrides the
* Content-Length. */
typedef int (*mio_htre_concb_t) (
mio_htre_t* re,
const mio_bch_t* ptr,
mio_oow_t len,
void* ctx
);
int cgi_forward_client_to_peer (mio_htre_t* re, const mio_bch_t* ptr, mio_oow_t len, void* ctx)
{
mio_dev_pro_t* pro = (mio_dev_pro_t*)ctx;
return mio_dev_pro_write(pro, ptr, len, MIO_NULL);
/* TODO: if there are too many pending write requests, stop read event on the client */
return -1; /* unable to determine content-length in advance */
}
else if (req->flags & MIO_HTRE_ATTR_LENGTH)
{
*len = req->attr.content_length;
}
else
{
/* no content */
*len = 0;
}
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_dev_pro_t* pro = MIO_NULL;
mio_t* mio = htts->mio;
mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(csck);
cgi_state_t* cgi_state = MIO_NULL;
cgi_peer_xtn_t* cgi_peer;
mio_oow_t req_content_length;
mio_dev_pro_make_t mi;
if (get_request_content_length(req, &req_content_length) <= -1)
{
/* chunked - the length is not know in advance */
/* don't start the process yet. */
/* option 1. send 411 Length Required */
/* option 2. support chunked message box in the request */
/* option 3[non standard]. set CONTENT_LENGTH to -1 and indicate the end of INPUT by sending EOF */
req_content_length = MIO_TYPE_MAX(mio_oow_t); /* TODO: change type or add another variable ? */
}
MIO_MEMSET (&mi, 0, MIO_SIZEOF(mi));
mi.flags = MIO_DEV_PRO_READOUT /*| MIO_DEV_PRO_READERR*/ | MIO_DEV_PRO_WRITEIN /*| MIO_DEV_PRO_FORGET_CHILD*/;
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;
/* TODO: create cgi environment variables... */
pro = mio_dev_pro_make(htts->mio, 0, &mi);
if (MIO_UNLIKELY(!pro)) goto oops;
cgi_state = mio_callocmem(mio, MIO_SIZEOF(*cgi_state));
if (MIO_UNLIKELY(!cgi_state)) goto oops;
/* THE process device must be ready for I/O */
if (mio_htre_getcontentlen(req) > 0)
cgi_state->htts = htts; /*TODO: delete this field after rsrd renewal? */
cgi_state->on_kill = cgi_state_on_kill;
cgi_state->cli = cli;
/*cgi_state->num_pending_writes_to_client = 0;
cgi_state->num_pending_writes_to_peer = 0;*/
cgi_state->req = req;
cgi_state->req_content_length = req_content_length;
cgi_state->cli_org_on_read = csck->on_read;
cgi_state->cli_org_on_write = csck->on_write;
csck->on_read = cgi_client_on_read;
csck->on_write = cgi_client_on_write;
RSRCL_APPEND_RSRC (&cli->rsrc, cgi_state); /* attach it to the client information */
/* TODO: create cgi environment variables... */
/* TODO:
* never put Expect: 100-continue to environment variable
*/
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);
cgi_peer->state = cgi_state;
cgi_state->peer_htrd = mio_htrd_open(mio, MIO_SIZEOF(*cgi_peer));
if (MIO_UNLIKELY(!cgi_state->peer_htrd)) goto oops;
cgi_peer = mio_htrd_getxtn(cgi_state->peer_htrd);
cgi_peer->state = cgi_state;
/* TODO: any other handling before this? */
/* I CAN't SIMPLY WRITE LIKE THIS, the cgi must require this.
* send contents depending how cgi want Expect: continue handling to be handled */
if (req->flags & MIO_HTRE_ATTR_EXPECT100)
{
if (mio_dev_pro_write(pro, mio_htre_getcontentptr(req), mio_htre_getcontentlen(req), MIO_NULL) <= -1) goto oops;
/* TODO: Expect: 100-continue? who should handle this? cgi? or the http server? */
if (mio_comp_http_version_numbers(&req->version, 1, 1) >= 0 && req_content_length > 0)
{
/*
* Don't send 100 Continue if http verions is lower than 1.1
* [RFC7231]
* A server that receives a 100-continue expectation in an HTTP/1.0
* request MUST ignore that expectation.
*
* Don't send 100 Continue if expected content lenth is 0.
* [RFC7231]
* A server MAY omit sending a 100 (Continue) response if it has
* already received some or all of the message body for the
* corresponding request, or if the framing indicates that there is
* no message body.
*/
cgi_state->num_pending_writes_to_client++;
if (mio_dev_sck_write(csck, "HTTP/1.1 100 Continue\r\n", 23, MIO_NULL, MIO_NULL) <= -1)
{
cgi_state->num_pending_writes_to_client--;
goto oops;
}
}
}
else if (req->flags & MIO_HTRE_ATTR_EXPECT)
{
mio_htre_discardcontent (req);
req->flags &= ~MIO_HTRE_ATTR_KEEPALIVE; /* to cause sendstatus() to close */
if (mio_svc_htts_sendstatus(htts, csck, req, 417, MIO_NULL) <= -1) goto oops;
}
mio_htre_setconcb (req, cgi_forward_client_to_peer, pro);
if (req_content_length > 0)
{
if (mio_htre_getcontentlen(req) > 0)
{
cgi_state->num_pending_writes_to_peer++;
if (mio_dev_pro_write(cgi_state->peer, mio_htre_getcontentptr(req), mio_htre_getcontentlen(req), MIO_NULL) <= -1)
{
cgi_state->num_pending_writes_to_peer--;
goto oops;
}
}
}
#if 0
csck->on_read = cgi_client_on_read;
cssk->on_write = cgi_client_on_write;
csck->on_disconnect = cgi_client_on_disconnect;
#endif
#if 0
rsrc = mio_svc_htts_rsrc_make(htts, csck, rsrc_cgi_on_read, rsrc_cgi_on_write, rsrc_cgi_on_kill, MIO_SIZEOF(*rsrc_cgi));
if (MIO_UNLIKELY(!rsrc)) goto oops;
#endif
if (req->state & (MIO_HTRE_COMPLETED | MIO_HTRE_DISCARDED))
{
/* disable input watching from the client */
if (mio_dev_sck_read(csck, 0) <= -1) goto oops;
}
return 0;
oops:
if (pro) mio_dev_pro_kill (pro);
MIO_DEBUG2 (mio, "HTTS(%p) - FAILURE in docgi - socket(%p)\n", htts, csck);
cgi_state->on_kill (cgi_state); /* TODO: call rsrc_free... */
mio_dev_sck_halt (csck);
return -1;
}
@ -1213,13 +1348,14 @@ oops:
return -1;
}
int mio_svc_htts_sendstatus (mio_svc_htts_t* htts, mio_dev_sck_t* csck, int status_code, mio_http_method_t method, const mio_http_version_t* version, int keepalive, void* extra)
int mio_svc_htts_sendstatus (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* req, int status_code, void* extra)
{
/* TODO: change this to use send status */
mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(csck);
mio_bch_t text[1024]; /* TODO: make this buffer dynamic or scalable */
mio_bch_t dtbuf[64];
mio_oow_t x;
mio_http_version_t* version = mio_htre_getversion(req);
const mio_bch_t* extrapre = "";
const mio_bch_t* extrapst = "";
@ -1279,7 +1415,7 @@ int mio_svc_htts_sendstatus (mio_svc_htts_t* htts, mio_dev_sck_t* csck, int stat
version->major, version->minor, status_code, mio_http_status_to_bcstr(status_code),
htts->server_name,
dtbuf, /* DATE */
(keepalive? "keep-alive": "close"), /* connection */
((req->flags & MIO_HTRE_ATTR_KEEPALIVE)? "keep-alive": "close"), /* connection */
mio_count_bcstr(text), /* content length */
extrapre, extraval, extraval, text
);
@ -1292,7 +1428,8 @@ int mio_svc_htts_sendstatus (mio_svc_htts_t* htts, mio_dev_sck_t* csck, int stat
mio_dev_sck_halt (csck);
return -1;
}
else if (!keepalive)
if (!(req->flags & MIO_HTRE_ATTR_KEEPALIVE))
{
/* arrange to close the writing end */
if (mio_dev_sck_write(csck, MIO_NULL, 0, MIO_NULL, MIO_NULL) <= -1)

View File

@ -179,8 +179,9 @@ MIO_EXPORT void mio_htrd_setrecbs (
*/
MIO_EXPORT int mio_htrd_feed (
mio_htrd_t* htrd, /**< htrd */
const mio_bch_t* req, /**< request octets */
mio_oow_t len /**< number of octets */
const mio_bch_t* req, /**< request octets */
mio_oow_t len, /**< number of octets */
mio_oow_t* rem
);
/**

View File

@ -37,7 +37,7 @@
*/
/* header and contents of request/response */
typedef struct mio_htre_t mio_htre_t;
/*typedef struct mio_htre_t mio_htre_t; <--- defined in mio-http.h TODO: remove recursive definition */
typedef struct mio_htre_hdrval_t mio_htre_hdrval_t;
enum mio_htre_state_t

View File

@ -156,6 +156,7 @@ typedef enum mio_perenc_http_opt_t mio_perenc_bcstr_opt_t;
/* -------------------------------------------------------------- */
typedef struct mio_htre_t mio_htre_t;
typedef struct mio_svc_htts_t mio_svc_htts_t;
typedef struct mio_svc_httc_t mio_svc_httc_t;
@ -164,6 +165,13 @@ typedef struct mio_svc_httc_t mio_svc_httc_t;
typedef struct mio_svc_htts_rsrc_t mio_svc_htts_rsrc_t;
typedef mio_uint64_t mio_foff_t ; /* TODO: define this via the main configure.ac ... */
typedef int (*mio_svc_htts_rsrc_on_read_t) (
mio_svc_htts_rsrc_t* rsrc,
mio_dev_sck_t* sck
);
typedef int (*mio_svc_htts_rsrc_on_write_t) (
mio_svc_htts_rsrc_t* rsrc,
mio_dev_sck_t* sck
@ -185,12 +193,14 @@ struct mio_svc_htts_rsrc_t
mio_svc_htts_rsrc_t* rsrc_prev;
mio_svc_htts_rsrc_t* rsrc_next;
mio_svc_htts_rsrc_on_kill_t on_kill;
mio_svc_htts_rsrc_on_write_t on_write;
int flags;
mio_bch_t* content_type;
mio_foff_t content_length;
mio_svc_htts_rsrc_on_write_t on_write;
mio_svc_htts_rsrc_on_kill_t on_kill;
};
/* -------------------------------------------------------------- */
@ -307,6 +317,14 @@ MIO_EXPORT int mio_svc_htts_setservernamewithbcstr (
);
MIO_EXPORT 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_EXPORT int mio_svc_htts_sendfile (
mio_svc_htts_t* htts,
mio_dev_sck_t* csck,
@ -320,10 +338,8 @@ MIO_EXPORT int mio_svc_htts_sendfile (
MIO_EXPORT int mio_svc_htts_sendstatus (
mio_svc_htts_t* htts,
mio_dev_sck_t* csck,
mio_htre_t* req,
int status_code,
mio_http_method_t method,
const mio_http_version_t* version,
int keepalive,
void* extra
);

View File

@ -298,6 +298,93 @@ static MIO_INLINE void unlink_wq (mio_t* mio, mio_wq_t* q)
MIO_WQ_UNLINK (q);
}
static void fire_cwq_handlers (mio_t* mio)
{
/* execute callbacks for completed write operations */
while (!MIO_CWQ_IS_EMPTY(&mio->cwq))
{
mio_cwq_t* cwq;
mio_oow_t cwqfl_index;
mio_dev_t* dev_to_halt;
cwq = MIO_CWQ_HEAD(&mio->cwq);
if (cwq->dev->dev_evcb->on_write(cwq->dev, cwq->olen, cwq->ctx, &cwq->dstaddr) <= -1)
{
MIO_DEBUG1 (mio, "MIO - Error returned by on_write() of device %p in cwq\n", cwq->dev);
dev_to_halt = cwq->dev;
}
else
{
dev_to_halt = MIO_NULL;
}
cwq->dev->cw_count--;
MIO_CWQ_UNLINK (cwq);
cwqfl_index = MIO_ALIGN_POW2(cwq->dstaddr.len, MIO_CWQFL_ALIGN) / MIO_CWQFL_SIZE;
if (cwqfl_index < MIO_COUNTOF(mio->cwqfl))
{
/* reuse the cwq object if dstaddr is 0 in size. chain it to the free list */
cwq->q_next = mio->cwqfl[cwqfl_index];
mio->cwqfl[cwqfl_index] = cwq;
}
else
{
/* TODO: more reuse of objects of different size? */
mio_freemem (mio, cwq);
}
if (dev_to_halt) mio_dev_halt (dev_to_halt);
}
}
static void fire_cwq_handlers_for_dev (mio_t* mio, mio_dev_t* dev)
{
mio_cwq_t* cwq, * next;
MIO_ASSERT (mio, dev->cw_count > 0); /* Ensure to check dev->cw_count before calling this function */
cwq = MIO_CWQ_HEAD(&mio->cwq);
while (cwq != &mio->cwq)
{
next = MIO_CWQ_NEXT(cwq);
if (cwq->dev == dev) /* TODO: THIS LOOP TOO INEFFICIENT??? MAINTAIN PER-DEVICE LIST OF CWQ? */
{
mio_dev_t* dev_to_halt;
mio_oow_t cwqfl_index;
if (cwq->dev->dev_evcb->on_write(cwq->dev, cwq->olen, cwq->ctx, &cwq->dstaddr) <= -1)
{
MIO_DEBUG1 (mio, "MIO - Error returned by on_write() of device %p in cwq\n", cwq->dev);
dev_to_halt = cwq->dev;
}
else
{
dev_to_halt = MIO_NULL;
}
cwq->dev->cw_count--;
MIO_CWQ_UNLINK (cwq);
cwqfl_index = MIO_ALIGN_POW2(cwq->dstaddr.len, MIO_CWQFL_ALIGN) / MIO_CWQFL_SIZE;
if (cwqfl_index < MIO_COUNTOF(mio->cwqfl))
{
/* reuse the cwq object if dstaddr is 0 in size. chain it to the free list */
cwq->q_next = mio->cwqfl[cwqfl_index];
mio->cwqfl[cwqfl_index] = cwq;
}
else
{
/* TODO: more reuse of objects of different size? */
mio_freemem (mio, cwq);
}
if (dev_to_halt) mio_dev_halt (dev_to_halt);
}
cwq = next;
}
}
static MIO_INLINE void handle_event (mio_t* mio, mio_dev_t* dev, int events, int rdhup)
{
MIO_ASSERT (mio, mio == dev->mio);
@ -389,7 +476,7 @@ static MIO_INLINE void handle_event (mio_t* mio, mio_dev_t* dev, int events, int
if (y <= -1)
{
MIO_DEBUG1 (mio, "Error returned by on_write() of device %p\n", dev);
MIO_DEBUG1 (mio, "MIO - Error returned by on_write() of device %p\n", dev);
mio_dev_halt (dev);
dev = MIO_NULL;
break;
@ -474,6 +561,19 @@ static MIO_INLINE void handle_event (mio_t* mio, mio_dev_t* dev, int events, int
}
else /*if (x >= 1) */
{
/* call on_write() callbacks enqueued fro the device before calling on_read().
* if on_write() callback is delayed, there can be out-of-order execution
* between on_read() and on_write() callbacks. for instance, if a write request
* is started from within on_read() callback, and the input data is available
* in the next iteration of this loop, the on_read() callback is triggered
* before the on_write() callbacks scheduled before that on_read() callback. */
if (dev->cw_count > 0)
{
fire_cwq_handlers_for_dev (mio, dev);
/* it will still invoke the on_read() callbak below even if
* the device gets halted inside fire_cwq_handlers_for_dev() */
}
if (len <= 0 && (dev->dev_cap & MIO_DEV_CAP_STREAM))
{
/* EOF received. for a stream device, a zero-length
@ -565,45 +665,15 @@ int mio_exec (mio_t* mio)
int ret = 0;
/* execute callbacks for completed write operations */
while (!MIO_CWQ_IS_EMPTY(&mio->cwq))
{
mio_cwq_t* cwq;
mio_oow_t cwqfl_index;
mio_dev_t* dev_to_halt;
cwq = MIO_CWQ_HEAD(&mio->cwq);
if (cwq->dev->dev_evcb->on_write(cwq->dev, cwq->olen, cwq->ctx, &cwq->dstaddr) <= -1)
{
MIO_DEBUG1 (mio, "Error returned by on_write() of device %p in cwq\n", cwq->dev);
dev_to_halt = cwq->dev;
}
else
{
dev_to_halt = MIO_NULL;
}
cwq->dev->cw_count--;
MIO_CWQ_UNLINK (cwq);
cwqfl_index = MIO_ALIGN_POW2(cwq->dstaddr.len, MIO_CWQFL_ALIGN) / MIO_CWQFL_SIZE;
if (cwqfl_index < MIO_COUNTOF(mio->cwqfl))
{
/* reuse the cwq object if dstaddr is 0 in size. chain it to the free list */
cwq->q_next = mio->cwqfl[cwqfl_index];
mio->cwqfl[cwqfl_index] = cwq;
}
else
{
/* TODO: more reuse of objects of different size? */
mio_freemem (mio, cwq);
}
if (dev_to_halt) mio_dev_halt (dev_to_halt);
}
fire_cwq_handlers (mio);
/* execute the scheduled jobs before checking devices with the
* multiplexer. the scheduled jobs can safely destroy the devices */
mio_firetmrjobs (mio, MIO_NULL, MIO_NULL);
/* execute callbacks for completed write operations again in case there were some jobs initiaated in the timer jobs */
//fire_cwq_handlers (mio);
if (!MIO_DEVL_IS_EMPTY(&mio->actdev))
{
/* wait on the multiplexer only if there is at least 1 active device */
@ -618,7 +688,7 @@ int mio_exec (mio_t* mio)
if (mio_sys_waitmux(mio, &tmout, handle_event) <= -1)
{
MIO_DEBUG0 (mio, "WARNING - Failed to wait on mutiplexer\n");
MIO_DEBUG0 (mio, "MIO - WARNING - Failed to wait on mutiplexer\n");
ret = -1;
}
}
@ -627,7 +697,7 @@ int mio_exec (mio_t* mio)
while (!MIO_DEVL_IS_EMPTY(&mio->hltdev))
{
mio_dev_t* dev = MIO_DEVL_FIRST_DEV(&mio->hltdev);
MIO_DEBUG1 (mio, "Killing HALTED device %p\n", dev);
MIO_DEBUG1 (mio, "MIO - Killing HALTED device %p\n", dev);
mio_dev_kill (dev);
}
@ -846,6 +916,7 @@ void mio_dev_kill (mio_dev_t* dev)
next = MIO_CWQ_NEXT(cwq);
if (cwq->dev == dev)
{
cwq->dev->cw_count--;
MIO_CWQ_UNLINK (cwq);
mio_freemem (mio, cwq);
}
@ -906,7 +977,7 @@ void mio_dev_halt (mio_dev_t* dev)
if (dev->dev_cap & MIO_DEV_CAP_ACTIVE)
{
MIO_DEBUG1 (mio, "HALTING DEVICE %p\n", dev);
MIO_DEBUG1 (mio, "MIO - HALTING DEVICE %p\n", dev);
/* delink the device object from the active device list */
MIO_DEVL_UNLINK_DEV (dev);

View File

@ -198,9 +198,9 @@ static pid_t standard_fork_and_exec (mio_t* mio, int pfds[], int flags, param_t*
(flags & MIO_DEV_PRO_ERRTONUL))
{
#if defined(O_LARGEFILE)
devnull = open ("/dev/null", O_RDWR | O_LARGEFILE, 0);
devnull = open("/dev/null", O_RDWR | O_LARGEFILE, 0);
#else
devnull = open ("/dev/null", O_RDWR, 0);
devnull = open("/dev/null", O_RDWR, 0);
#endif
if (devnull == MIO_SYSHND_INVALID) goto slave_oops;
}
@ -224,7 +224,7 @@ static int dev_pro_make_master (mio_dev_t* dev, void* ctx)
mio_t* mio = dev->mio;
mio_dev_pro_t* rdev = (mio_dev_pro_t*)dev;
mio_dev_pro_make_t* info = (mio_dev_pro_make_t*)ctx;
mio_syshnd_t pfds[6];
mio_syshnd_t pfds[6] = { MIO_SYSHND_INVALID, MIO_SYSHND_INVALID, MIO_SYSHND_INVALID, MIO_SYSHND_INVALID, MIO_SYSHND_INVALID, MIO_SYSHND_INVALID };
int i, minidx = -1, maxidx = -1;
param_t param;
pid_t pid;
@ -459,7 +459,7 @@ static int dev_pro_kill_master (mio_dev_t* dev, int force)
int killed = 0;
await_child:
wpid = waitpid (rdev->child_pid, &status, WNOHANG);
wpid = waitpid(rdev->child_pid, &status, WNOHANG);
if (wpid == 0)
{
if (force && !killed)