in the midst of debugging http server code

This commit is contained in:
2020-05-20 10:25:12 +00:00
parent 914dd35b37
commit d95bc9bc92
11 changed files with 253 additions and 128 deletions

View File

@ -9,6 +9,7 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <pthread.h>
#include <stdlib.h> /* 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)