still working on cgi handling in http server

This commit is contained in:
hyung-hwan 2020-05-19 09:11:39 +00:00
parent 362ae444fc
commit fc26f4a6c3
9 changed files with 294 additions and 104 deletions

View File

@ -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)
{

View File

@ -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);
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 */
}
else
{
MIO_ASSERT (mio, cgi_state->peer == pro);
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)
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))
{
/* 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)
{
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:

View File

@ -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
);

View File

@ -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;
}

View File

@ -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);

View File

@ -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++;

13
mio/t/t1.txt Normal file
View File

@ -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

15
mio/t/t2.txt Normal file
View File

@ -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

13
mio/t/t3.txt Normal file
View File

@ -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