From a2d047a676ecbd794e60dae9f3d31b7df9ffbb70 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Mon, 20 Feb 2023 17:08:41 +0900 Subject: [PATCH] fixed more issues in fcgi handling --- bin/t01.c | 2 +- bin/t06.c | 2 +- bin/webs.c | 27 +++++++++-- lib/fcgi-cli.c | 34 ++++++-------- lib/hio-cmn.h | 8 ++++ lib/hio-ecs.h | 3 ++ lib/hio-htre.h | 1 + lib/hio-http.h | 11 +++-- lib/hio.c | 11 +++++ lib/hio.h | 10 ++-- lib/http-cgi.c | 45 +++++++++++++++--- lib/http-fcgi.c | 122 +++++++++++++++++++++++++++++++++++++++++------- lib/http-prv.h | 3 ++ lib/http-svr.c | 15 ++++-- 14 files changed, 231 insertions(+), 63 deletions(-) diff --git a/bin/t01.c b/bin/t01.c index ae3c2cc..f43f6dd 100644 --- a/bin/t01.c +++ b/bin/t01.c @@ -1245,7 +1245,7 @@ for (i = 0; i < 5; i++) HIO_INFO1 (hio, "UNABLE TO START DNC - %js\n", hio_geterrmsg(hio)); } - htts = hio_svc_htts_start(hio, 0, &htts_bind_info, 1, process_http_request); + htts = hio_svc_htts_start(hio, 0, &htts_bind_info, 1, process_http_request, HIO_NULL); if (htts) hio_svc_htts_setservernamewithbcstr (htts, "HIO-HTTP"); else HIO_INFO1 (hio, "UNABLE TO START HTTS - %js\n", hio_geterrmsg(hio)); diff --git a/bin/t06.c b/bin/t06.c index 6afb6cb..93b6ec4 100644 --- a/bin/t06.c +++ b/bin/t06.c @@ -252,7 +252,7 @@ void* thr_func (void* arg) htts_bind_info[1].ssl_keyfile = "localhost.key"; #endif - htts = hio_svc_htts_start(hio, 0, htts_bind_info, HIO_COUNTOF(htts_bind_info), process_http_request); + htts = hio_svc_htts_start(hio, 0, htts_bind_info, HIO_COUNTOF(htts_bind_info), process_http_request, HIO_NULL); if (!htts) { printf ("Unable to start htts\n"); diff --git a/bin/webs.c b/bin/webs.c index 6b19c26..0eb5930 100644 --- a/bin/webs.c +++ b/bin/webs.c @@ -304,6 +304,7 @@ static int process_http_request (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_ hio_t* hio = hio_svc_htts_gethio(htts); hio_http_method_t mth; const hio_bch_t* qpath, * qpath_ext; + int proto_len; static hio_svc_htts_file_cbs_t fcbs = { file_get_mime_type, file_open_dir_list, HIO_NULL }; @@ -314,6 +315,19 @@ static int process_http_request (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_ qpath_ext = hio_rfind_bchar_in_bcstr(qpath, '.'); if (!qpath_ext) qpath_ext = ""; + /* TODO: log remote address and other information .... */ + HIO_INFO3 (hio, "%.*hs %hs\n", hio_htre_getqmethodlen(req), hio_htre_getqmethodname(req), qpath); + + if (((proto_len = 7) && hio_comp_bcstr_limited(qpath, "http://", 7, 1) == 0) || + ((proto_len = 8) && hio_comp_bcstr_limited(qpath, "https://", 8, 1) == 0)) + { + const hio_bch_t* tmp; + tmp = hio_find_bchar_in_bcstr(qpath + proto_len, '/'); + if (tmp) qpath = tmp; /* skip http://domain.name */ + + /* TODO: support proxy .... */ + } + if (mth == HIO_HTTP_OTHER && hio_comp_bcstr(hio_htre_getqmethodname(req), "UNTAR", 1) == 0 && hio_comp_bcstr(qpath_ext, ".tar", 0) == 0) { /* don't care about the path for now. TODO: make this secure and reasonable */ @@ -330,15 +344,17 @@ static int process_http_request (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_ { if (hio_svc_htts_docgi(htts, csck, req, ext->ai->docroot, qpath, 0) <= -1) goto oops; } - else if (hio_comp_bcstr(qpath_ext, ".php", 0) == 0) + else if (hio_comp_bcstr(qpath_ext, ".php", 0) == 0 || hio_comp_bcstr(qpath_ext, ".ant", 0) == 0 /*|| hio_comp_bcstr_limited(qpath, "http://", 7, 1) == 0*/) { hio_skad_t skad; hio_bcstrtoskad(hio, "10.30.0.133:9000", &skad); + + HIO_DEBUG2 (hio, "fcgi %hs %hs\n", ext->ai->docroot, qpath); /*if (hio_svc_htts_dofcgi(htts, csck, req, &skad, ext->ai->docroot, qpath, 0) <= -1) goto oops;*/ /* if the document root is relative, it is hard to gurantee that the same document is * true to the fcgi server which is a different process. so map it a blank string for now. * TODO: accept a separate document root for the fcgi server and use it below */ - if (hio_svc_htts_dofcgi(htts, csck, req, &skad, "", qpath, 0) <= -1) goto oops; + if (hio_svc_htts_dofcgi(htts, csck, req, &skad, ext->ai->docroot, qpath, 0) <= -1) goto oops; /*if (hio_svc_htts_dotxt(htts, csck, req, HIO_HTTP_STATUS_INTERNAL_SERVER_ERROR, "text/plain", "what the...", 0) <= -1) goto oops;*/ } else // if (mth == HIO_HTTP_GET || mth == HIO_HTTP_POST) @@ -368,6 +384,7 @@ int webs_start (hio_t* hio, const arg_info_t* ai) hio_oow_t bic; hio_svc_htts_t* webs; htts_ext_t* ext; + hio_svc_fcgic_tmout_t fcgic_tmout; bic = 0; ptr = ai->laddrs; @@ -389,7 +406,11 @@ int webs_start (hio_t* hio, const arg_info_t* ai) } } - webs = hio_svc_htts_start(hio, HIO_SIZEOF(htts_ext_t), bi, bic, process_http_request); + HIO_MEMSET (&fcgic_tmout, 0, HIO_SIZEOF(fcgic_tmout)); + fcgic_tmout.c.sec = 5; + fcgic_tmout.r.sec = 60; + + webs = hio_svc_htts_start(hio, HIO_SIZEOF(htts_ext_t), bi, bic, process_http_request, &fcgic_tmout); if (!webs) return -1; /* TODO: logging */ ext = hio_svc_htts_getxtn(webs); diff --git a/lib/fcgi-cli.c b/lib/fcgi-cli.c index c78fea7..f2b505d 100644 --- a/lib/fcgi-cli.c +++ b/lib/fcgi-cli.c @@ -88,7 +88,7 @@ struct fcgic_sck_xtn_t }; typedef struct fcgic_sck_xtn_t fcgic_sck_xtn_t; -static int make_connection_socket (hio_svc_fcgic_conn_t* conn); +static int make_connection_socket (hio_svc_fcgic_t* fcigc, hio_svc_fcgic_conn_t* conn); static void release_session (hio_svc_fcgic_sess_t* sess); static void sck_on_disconnect (hio_dev_sck_t* sck) @@ -100,15 +100,6 @@ printf ("DISCONNECT SOCKET .................. sck->%p conn->%p\n", sck, conn); if (conn) { -/* TODO: arrange to create it again if the server is not closing... */ -/* if (.... ) */ -#if 0 - if (sck->hio->stopreq == HIO_STOPREQ_NONE) - { - /* this may create a busy loop if the connection attempt fails repeatedly */ - make_connection_socket(conn); /* don't care about failure for now */ - } -#else hio_oow_t i; for (i = 0; i < conn->sess.capa; i++) { @@ -120,7 +111,6 @@ printf ("DISCONNECT SOCKET .................. sck->%p conn->%p\n", sck, conn); } } conn->dev = HIO_NULL; -#endif } } @@ -129,11 +119,14 @@ static void sck_on_connect (hio_dev_sck_t* sck) fcgic_sck_xtn_t* sck_xtn = hio_dev_sck_getxtn(sck); hio_svc_fcgic_conn_t* conn = sck_xtn->conn; -printf ("CONNECTED >>>>>>>>>>>>>>>>>>>>>>>>>>\n"); +printf ("FCGIC SOCKET CONNECTED >>>>>>>>>>>>>>>>>>>>>>>>>>\n"); /* reinitialize the input parsing information */ HIO_MEMSET (&conn->r, 0, HIO_SIZEOF(conn->r)); conn->r.state = R_AWAITING_HEADER; + + if (conn->fcgic->tmout_set) + hio_dev_sck_timedread (sck, 1, &conn->fcgic->tmout.r); } static int sck_on_write (hio_dev_sck_t* sck, hio_iolen_t wrlen, void* wrctx, const hio_skad_t* dstaddr) @@ -237,10 +230,12 @@ static int sck_on_read (hio_dev_sck_t* sck, const void* data, hio_iolen_t dlen, if (!sess || !sess->active) { /* discard the record. no associated sessoin or inactive session */ -printf ("UNKNOWN SESSION ..................... %p %d\n", sess, conn->r.id); +HIO_DEBUG2 (hio, "UNKNOWN SESSION ..................... %p %d\n", sess, conn->r.id); +if (sess) HIO_DEBUG1 (hio, "UNKNOWN SESSION active? %d\n", sess->active); goto back_to_header; } +HIO_DEBUG2 (hio, "OK SESSION ..................... %p %d\n", sess, conn->r.id); /* the complete body is in conn->r.buf */ if (conn->r.type == HIO_FCGI_END_REQUEST) { @@ -278,7 +273,7 @@ done: return 0; } -static int make_connection_socket (hio_svc_fcgic_conn_t* conn) +static int make_connection_socket (hio_svc_fcgic_t* fcgic, hio_svc_fcgic_conn_t* conn) { hio_t* hio = conn->fcgic->hio; hio_dev_sck_t* sck; @@ -322,7 +317,7 @@ static int make_connection_socket (hio_svc_fcgic_conn_t* conn) HIO_MEMSET (&ci, 0, HIO_SIZEOF(ci)); ci.remoteaddr = conn->addr; - ci.connect_tmout.sec = 5; /* TODO: make this configurable */ + if (fcgic->tmout_set) ci.connect_tmout = fcgic->tmout.c; if (hio_dev_sck_connect(sck, &ci) <= -1) { @@ -350,7 +345,7 @@ static hio_svc_fcgic_conn_t* get_connection (hio_svc_fcgic_t* fcgic, const hio_s if (!conn->sess.free || conn->sess.capa <= (CONN_SESS_CAPA_MAX - CONN_SESS_INC)) { /* the connection has room for more sessions */ - if (!conn->dev) make_connection_socket(conn); /* conn->dev will still be null if connection fails*/ + if (!conn->dev) make_connection_socket(fcgic, conn); /* conn->dev will still be null if connection fails*/ return conn; } } @@ -365,7 +360,7 @@ static hio_svc_fcgic_conn_t* get_connection (hio_svc_fcgic_t* fcgic, const hio_s conn->sess.capa = 0; conn->sess.free = HIO_NULL; - if (make_connection_socket(conn) <= -1) + if (make_connection_socket(fcgic, conn) <= -1) { hio_freemem (hio, conn); return HIO_NULL; @@ -598,7 +593,7 @@ int hio_svc_fcgic_writeparam (hio_svc_fcgic_sess_t* sess, const void* key, hio_i vsz &= HIO_TYPE_MAX(hio_int32_t); if (ksz > 0) { - if (ksz > 0xFF) + if (ksz > 0x7F) { sz[szc++] = (ksz >> 24) | 0x80; sz[szc++] = (ksz >> 16) & 0xFF; @@ -610,7 +605,7 @@ int hio_svc_fcgic_writeparam (hio_svc_fcgic_sess_t* sess, const void* key, hio_i sz[szc++] = ksz; } - if (vsz > 0xFF) + if (vsz > 0x7F) { sz[szc++] = (vsz >> 24) | 0x80; sz[szc++] = (vsz >> 16) & 0xFF; @@ -650,7 +645,6 @@ int hio_svc_fcgic_writestdin (hio_svc_fcgic_sess_t* sess, const void* data, hio_ hio_iovec_t iov[2]; hio_fcgi_record_header_t h; -printf (">>>>>>>>>>>>>>>>>>>>>>[%p] %p\n", sess, sess->conn); if (!sess->conn->dev) { /* TODO: set error **/ diff --git a/lib/hio-cmn.h b/lib/hio-cmn.h index c003aa6..0229567 100644 --- a/lib/hio-cmn.h +++ b/lib/hio-cmn.h @@ -1038,4 +1038,12 @@ struct hio_cmgr_t ((c) >= 'A' && (c) <= 'Z')? ((c) - 'A' + 10): \ ((c) >= 'a' && (c) <= 'Z')? ((c) - 'a' + 10): base) + +/* ========================================================================= + * PRE-DEFINITION OF FOUNDATIONAL COMPOSITE TYPES + * =========================================================================*/ +typedef struct hio_t hio_t; +typedef struct hio_becs_t hio_becs_t; +typedef struct hio_uecs_t hio_uecs_t; + #endif diff --git a/lib/hio-ecs.h b/lib/hio-ecs.h index 533845f..6d0df36 100644 --- a/lib/hio-ecs.h +++ b/lib/hio-ecs.h @@ -60,8 +60,11 @@ /**< last character. unsafe if length <= 0 */ #define HIO_UECS_LASTCHAR(s) ((s)->val.ptr[(s)->val.len-1]) +/* + * defined in hio-cmn.h typedef struct hio_becs_t hio_becs_t; typedef struct hio_uecs_t hio_uecs_t; +*/ typedef hio_oow_t (*hio_becs_sizer_t) ( hio_becs_t* data, diff --git a/lib/hio-htre.h b/lib/hio-htre.h index 895f476..affdbe8 100644 --- a/lib/hio-htre.h +++ b/lib/hio-htre.h @@ -108,6 +108,7 @@ enum hio_http_status_t HIO_HTTP_STATUS_PARTIAL_CONTENT = 206, HIO_HTTP_STATUS_MOVED_PERMANENTLY = 301, + HIO_HTTP_STATUS_MOVED_TEMPORARILY = 302, HIO_HTTP_STATUS_NOT_MODIFIED = 304, HIO_HTTP_STATUS_BAD_REQUEST = 400, diff --git a/lib/hio-http.h b/lib/hio-http.h index 570f53c..a78101f 100644 --- a/lib/hio-http.h +++ b/lib/hio-http.h @@ -354,11 +354,12 @@ HIO_EXPORT hio_oow_t hio_escape_html_bcstr ( /* ------------------------------------------------------------------------- */ HIO_EXPORT hio_svc_htts_t* hio_svc_htts_start ( - hio_t* hio, - hio_oow_t xtnsize, - hio_dev_sck_bind_t* binds, - hio_oow_t nbinds, - hio_svc_htts_proc_req_t proc_req + hio_t* hio, + hio_oow_t xtnsize, + hio_dev_sck_bind_t* binds, + hio_oow_t nbinds, + hio_svc_htts_proc_req_t proc_req, + const hio_svc_fcgic_tmout_t* fcgic_tmout ); HIO_EXPORT void hio_svc_htts_stop ( diff --git a/lib/hio.c b/lib/hio.c index d3c20cb..87a22cb 100644 --- a/lib/hio.c +++ b/lib/hio.c @@ -24,6 +24,7 @@ #include "hio-prv.h" #include +#include #include /* malloc, free, etc */ #define DEV_CAP_ALL_WATCHED (HIO_DEV_CAP_IN_WATCHED | HIO_DEV_CAP_OUT_WATCHED | HIO_DEV_CAP_PRI_WATCHED) @@ -123,6 +124,9 @@ int hio_init (hio_t* hio, hio_mmgr_t* mmgr, hio_cmgr_t* cmgr, hio_bitmask_t feat hio->log.ptr = hio_allocmem(hio, (hio->log.capa + 1) * HIO_SIZEOF(*hio->log.ptr)); if (HIO_UNLIKELY(!hio->log.ptr)) goto oops; + hio->becbuf = hio_becs_open(hio, 0, 256); + if (HIO_UNLIKELY(!hio->becbuf)) goto oops; + /* inititalize the system-side logging */ if (HIO_UNLIKELY(hio_sys_init(hio) <= -1)) goto oops; sys_inited = 1; @@ -149,6 +153,7 @@ oops: if (sys_inited) hio_sys_fini (hio); + if (hio->becbuf) hio_freemem (hio, hio->becbuf); if (hio->log.ptr) hio_freemem (hio, hio->log.ptr); hio->log.capa = 0; return -1; @@ -245,6 +250,12 @@ void hio_fini (hio_t* hio) hio_sys_fini (hio); /* finalize the system dependent data */ + if (hio->becbuf) + { + hio_becs_close (hio->becbuf); + hio->becbuf = HIO_NULL; + } + if (hio->log.ptr) { hio_freemem (hio, hio->log.ptr); diff --git a/lib/hio.h b/lib/hio.h index 3860ca1..308f6dc 100644 --- a/lib/hio.h +++ b/lib/hio.h @@ -54,7 +54,10 @@ struct hio_devaddr_t /* ========================================================================= */ -typedef struct hio_t hio_t; +/* + * defined in hio-cmn.h + *typedef struct hio_t hio_t; + */ typedef struct hio_dev_t hio_dev_t; typedef struct hio_dev_mth_t hio_dev_mth_t; typedef struct hio_dev_evcb_t hio_dev_evcb_t; @@ -734,6 +737,7 @@ struct hio_t hio_bitmask_t _features; + hio_stopreq_t stopreq; /* stop request to abort hio_loop() */ unsigned short int _shuterr; unsigned short int _fini_in_progress; @@ -766,14 +770,14 @@ struct hio_t } xbuf; /* buffer to support sprintf */ } sprintf; - hio_stopreq_t stopreq; /* stop request to abort hio_loop() */ + hio_becs_t* becbuf; /* temporary buffer for some string manipulation */ + hio_uint8_t bigbuf[65535]; /* TODO: make this dynamic depending on devices added. device may indicate a buffer size required??? */ hio_cfmb_t cfmb; /* list head of cfmbs */ hio_dev_t actdev; /* list head of active devices */ hio_dev_t hltdev; /* list head of halted devices */ hio_dev_t zmbdev; /* list head of zombie devices */ - hio_uint8_t bigbuf[65535]; /* TODO: make this dynamic depending on devices added. device may indicate a buffer size required??? */ hio_ntime_t init_time; struct diff --git a/lib/http-cgi.c b/lib/http-cgi.c index 5eb3332..667309d 100644 --- a/lib/http-cgi.c +++ b/lib/http-cgi.c @@ -479,6 +479,7 @@ static int peer_htrd_peek (hio_htrd_t* htrd, hio_htre_t* req) hio_svc_htts_cli_t* cli = cgi->client; hio_bch_t dtbuf[64]; int status_code = HIO_HTTP_STATUS_OK; + const hio_bch_t* status_line = HIO_NULL; if (req->attr.content_length) { @@ -489,19 +490,49 @@ static int peer_htrd_peek (hio_htrd_t* htrd, hio_htre_t* req) if (req->attr.status) { int is_sober; - const hio_bch_t* endptr; + const hio_bch_t* begptr, * endptr; hio_intmax_t v; + hio_oow_t code_len; + hio_oow_t desc_len; - v = hio_bchars_to_intmax(req->attr.status, hio_count_bcstr(req->attr.status), HIO_BCHARS_TO_INTMAX_MAKE_OPTION(0,0,0,10), &endptr, &is_sober); - if (*endptr == '\0' && is_sober && v > 0 && v <= HIO_TYPE_MAX(int)) status_code = v; + endptr = req->attr.status; + while (hio_is_bch_space(*endptr)) endptr++; + begptr = endptr; + while (hio_is_bch_digit(*endptr)) endptr++; + code_len = endptr - begptr; + + while (hio_is_bch_space(*endptr)) endptr++; + begptr = endptr; + while (*endptr != '\0') endptr++; + desc_len = endptr - begptr; + + /* the status line could be simply "Status: 302" or more verbose like "Status: 302 Moved" + * the value may contain more than numbers */ + if (code_len > 0 && desc_len > 0) + { + status_line = req->attr.status; + } + else + { + v = hio_bchars_to_intmax(req->attr.status, hio_count_bcstr(req->attr.status), HIO_BCHARS_TO_INTMAX_MAKE_OPTION(0,0,0,10), &endptr, &is_sober); + if (*endptr == '\0' && is_sober && v > 0 && v <= HIO_TYPE_MAX(int)) status_code = v; + } } hio_svc_htts_fmtgmtime (cli->htts, HIO_NULL, dtbuf, HIO_COUNTOF(dtbuf)); - if (hio_becs_fmt(cli->sbuf, "HTTP/%d.%d %d %hs\r\nServer: %hs\r\nDate: %hs\r\n", - cgi->req_version.major, cgi->req_version.minor, - status_code, hio_http_status_to_bcstr(status_code), - cli->htts->server_name, dtbuf) == (hio_oow_t)-1) return -1; + if (hio_becs_fmt(cli->sbuf, "HTTP/%d.%d ", cgi->req_version.major, cgi->req_version.minor) == (hio_oow_t)-1) return -1; + if (status_line) + { + if (hio_becs_fcat(cli->sbuf, "%hs\r\n", status_line) == (hio_oow_t)-1) return -1; + } + else + { + if (hio_becs_fcat(cli->sbuf, "%d %hs\r\n", status_code, hio_http_status_to_bcstr(status_code)) == (hio_oow_t)-1) return -1; + } + + if (hio_becs_fcat(cli->sbuf, "Server: %hs\r\nDate: %hs\r\n", cli->htts->server_name, dtbuf) == (hio_oow_t)-1) return -1; + if (hio_htre_walkheaders(req, peer_capture_response_header, cli) <= -1) return -1; diff --git a/lib/http-fcgi.c b/lib/http-fcgi.c index 5f129bb..ff85fa4 100644 --- a/lib/http-fcgi.c +++ b/lib/http-fcgi.c @@ -14,11 +14,9 @@ enum fcgi_res_mode_t }; typedef enum fcgi_res_mode_t fcgi_res_mode_t; - #define FCGI_PENDING_IO_THRESHOLD_TO_CLIENT 50 #define FCGI_PENDING_IO_THRESHOLD_TO_PEER 50 - #define FCGI_OVER_READ_FROM_CLIENT (1 << 0) #define FCGI_OVER_READ_FROM_PEER (1 << 1) #define FCGI_OVER_WRITE_TO_CLIENT (1 << 2) @@ -69,7 +67,7 @@ static void unbind_task_from_peer (fcgi_t* fcgi, int rcdown); static void fcgi_halt_participating_devices (fcgi_t* fcgi) { /* TODO: include fcgi session id in the output in place of peer??? */ - HIO_DEBUG5 (fcgi->htts->hio, "HTTS(%p) - cgi(t=%p,c=%p(%d),p=%p) Halting participating devices\n", fcgi->htts, fcgi, fcgi->csck, (fcgi->csck? fcgi->csck->hnd: -1), fcgi->peer); + HIO_DEBUG5 (fcgi->htts->hio, "HTTS(%p) - fcgi(t=%p,c=%p(%d),p=%p) Halting participating devices\n", fcgi->htts, fcgi, fcgi->csck, (fcgi->csck? fcgi->csck->hnd: -1), fcgi->peer); if (fcgi->csck) hio_dev_sck_halt (fcgi->csck); unbind_task_from_peer (fcgi, 1); @@ -81,6 +79,7 @@ static int fcgi_write_to_client (fcgi_t* fcgi, const void* data, hio_iolen_t dle { fcgi->ever_attempted_to_write_to_client = 1; +HIO_DEBUG2 (fcgi->htts->hio, "WR TO C[%.*hs]\n", dlen, data); fcgi->num_pending_writes_to_client++; if (hio_dev_sck_write(fcgi->csck, data, dlen, HIO_NULL, HIO_NULL) <= -1) { @@ -138,7 +137,7 @@ static int fcgi_send_final_status_to_client (fcgi_t* fcgi, int status_code, int const hio_bch_t* status_msg; hio_oow_t content_len; - if (!cli) return; /* client unbound or no binding client */ + if (!cli) return 0; /* client unbound or no binding client */ hio_svc_htts_fmtgmtime (cli->htts, HIO_NULL, dtbuf, HIO_COUNTOF(dtbuf)); status_msg = hio_http_status_to_bcstr(status_code); @@ -249,10 +248,9 @@ static HIO_INLINE void fcgi_mark_over (fcgi_t* fcgi, int over_bits) { if (fcgi->keep_alive && !fcgi->client_eof_detected) { -/* how to arrange to delete this fcgi object and put the socket back to the normal waiting state??? */ + HIO_DEBUG2 (hio, "HTTS(%p) - keeping client(%p) alive\n", fcgi->htts, fcgi->csck); HIO_ASSERT (fcgi->htts->hio, fcgi->client->task == (hio_svc_htts_task_t*)fcgi); unbind_task_from_client (fcgi, 1); - /* fcgi must not be accessed from here down as it could have been destroyed in unbind_task_from_client() */ } else @@ -305,13 +303,17 @@ static void fcgi_on_kill (hio_svc_htts_task_t* task) static void fcgi_peer_on_untie (hio_svc_fcgic_sess_t* peer, void* ctx) { fcgi_t* fcgi = (fcgi_t*)ctx; + hio_t* hio = fcgi->htts->hio; /* in case this untie event originates from the fcgi client itself. * fcgi_halt_participating_devices() calls hio_svc_fcgi_untie() again * to cause an infinite loop if we don't reset fcgi->peer to HIO_NULL here */ + + HIO_DEBUG5 (hio, "HTTS(%p) - fcgi(t=%p,c=%p[%d],p=%p) - peer untied\n", fcgi->htts, fcgi, fcgi->client, (fcgi->csck? fcgi->csck->hnd: -1), fcgi->peer); + fcgi->peer = HIO_NULL; fcgi_write_last_chunk_to_client (fcgi); - fcgi_halt_participating_devices (fcgi); /* TODO: kill the session only??? */ + unbind_task_from_peer (fcgi, 1); } static int fcgi_peer_on_read (hio_svc_fcgic_sess_t* peer, const void* data, hio_iolen_t dlen, void* ctx) @@ -412,6 +414,7 @@ static int peer_htrd_peek (hio_htrd_t* htrd, hio_htre_t* req) hio_svc_htts_cli_t* cli = fcgi->client; hio_bch_t dtbuf[64]; int status_code = HIO_HTTP_STATUS_OK; + const hio_bch_t* status_line = HIO_NULL; if (req->attr.content_length) { @@ -422,19 +425,48 @@ static int peer_htrd_peek (hio_htrd_t* htrd, hio_htre_t* req) if (req->attr.status) { int is_sober; - const hio_bch_t* endptr; + const hio_bch_t* begptr, * endptr; hio_intmax_t v; + hio_oow_t code_len; + hio_oow_t desc_len; - v = hio_bchars_to_intmax(req->attr.status, hio_count_bcstr(req->attr.status), HIO_BCHARS_TO_INTMAX_MAKE_OPTION(0,0,0,10), &endptr, &is_sober); - if (*endptr == '\0' && is_sober && v > 0 && v <= HIO_TYPE_MAX(int)) status_code = v; + endptr = req->attr.status; + while (hio_is_bch_space(*endptr)) endptr++; + begptr = endptr; + while (hio_is_bch_digit(*endptr)) endptr++; + code_len = endptr - begptr; + + while (hio_is_bch_space(*endptr)) endptr++; + begptr = endptr; + while (*endptr != '\0') endptr++; + desc_len = endptr - begptr; + + /* the status line could be simply "Status: 302" or more verbose like "Status: 302 Moved" + * the value may contain more than numbers */ + if (code_len > 0 && desc_len > 0) + { + status_line = req->attr.status; + } + else + { + v = hio_bchars_to_intmax(req->attr.status, hio_count_bcstr(req->attr.status), HIO_BCHARS_TO_INTMAX_MAKE_OPTION(0,0,0,10), &endptr, &is_sober); + if (*endptr == '\0' && is_sober && v > 0 && v <= HIO_TYPE_MAX(int)) status_code = v; + } } hio_svc_htts_fmtgmtime (cli->htts, HIO_NULL, dtbuf, HIO_COUNTOF(dtbuf)); - if (hio_becs_fmt(cli->sbuf, "HTTP/%d.%d %d %hs\r\nServer: %hs\r\nDate: %hs\r\n", - fcgi->req_version.major, fcgi->req_version.minor, - status_code, hio_http_status_to_bcstr(status_code), - cli->htts->server_name, dtbuf) == (hio_oow_t)-1) return -1; + if (hio_becs_fmt(cli->sbuf, "HTTP/%d.%d ", fcgi->req_version.major, fcgi->req_version.minor) == (hio_oow_t)-1) return -1; + if (status_line) + { + if (hio_becs_fcat(cli->sbuf, "%hs\r\n", status_line) == (hio_oow_t)-1) return -1; + } + else + { + if (hio_becs_fcat(cli->sbuf, "%d %hs\r\n", status_code, hio_http_status_to_bcstr(status_code)) == (hio_oow_t)-1) return -1; + } + + if (hio_becs_fcat(cli->sbuf, "Server: %hs\r\nDate: %hs\r\n", cli->htts->server_name, dtbuf) == (hio_oow_t)-1) return -1; if (hio_htre_walkheaders(req, peer_capture_response_header, cli) <= -1) return -1; @@ -698,6 +730,56 @@ oops: return 0; } +static int peer_capture_request_header (hio_htre_t* req, const hio_bch_t* key, const hio_htre_hdrval_t* val, void* ctx) +{ + fcgi_t* fcgi = (fcgi_t*)ctx; + hio_svc_htts_t* htts = fcgi->htts; + hio_t* hio = htts->hio; + + if (hio_comp_bcstr(key, "Connection", 1) != 0 && + hio_comp_bcstr(key, "Transfer-Encoding", 1) != 0 && + hio_comp_bcstr(key, "Content-Length", 1) != 0 && + hio_comp_bcstr(key, "Expect", 1) != 0) + { + hio_oow_t val_offset; + hio_bch_t* ptr; + + if (hio_comp_bcstr(key, "Content-Type", 1) == 0) + { + /* don't prefix CONTENT_TYPE with HTTP_ */ + hio_becs_clear (hio->becbuf); + } + else + { + if (hio_becs_cpy(hio->becbuf, "HTTP_") == (hio_oow_t)-1) return -1; + } + + if (hio_becs_cat(hio->becbuf, key) == (hio_oow_t)-1 || + hio_becs_ccat(hio->becbuf, '\0') == (hio_oow_t)-1) return -1; + + for (ptr = HIO_BECS_PTR(hio->becbuf); *ptr; ptr++) + { + *ptr = hio_to_bch_upper(*ptr); + if (*ptr =='-') *ptr = '_'; + } + + val_offset = HIO_BECS_LEN(hio->becbuf); + if (hio_becs_cat(hio->becbuf, val->ptr) == (hio_oow_t)-1) return -1; + val = val->next; + while (val) + { + if (hio_becs_cat(hio->becbuf, ",") == (hio_oow_t)-1 || + hio_becs_cat(hio->becbuf, val->ptr) == (hio_oow_t)-1) return -1; + val = val->next; + } + + hio_svc_fcgic_writeparam(fcgi->peer, HIO_BECS_PTR(hio->becbuf), val_offset - 1, HIO_BECS_CPTR(hio->becbuf, val_offset), HIO_BECS_LEN(hio->becbuf) - val_offset); + /* TODO: error handling? */ + } + + return 0; +} + static int write_params (fcgi_t* fcgi, hio_dev_sck_t* csck, hio_htre_t* req, const hio_bch_t* docroot, const hio_bch_t* script) { @@ -707,6 +789,7 @@ static int write_params (fcgi_t* fcgi, hio_dev_sck_t* csck, hio_htre_t* req, con const hio_bch_t* qparam; hio_oow_t content_length; hio_bch_t* actual_script = HIO_NULL; + hio_becs_t dbuf; HIO_ASSERT (hio, fcgi->csck == csck); @@ -727,7 +810,8 @@ static int write_params (fcgi_t* fcgi, hio_dev_sck_t* csck, hio_htre_t* req, con if (hio_svc_fcgic_writeparam(fcgi->peer, "REQUEST_URI", 11, hio_htre_getqpath(req), hio_htre_getqpathlen(req)) <= -1) goto oops; qparam = hio_htre_getqparam(req); - if (qparam && hio_svc_fcgic_writeparam(fcgi->peer, "QUERY_STRING", 12, qparam, hio_count_bcstr(qparam)) <= -1) goto oops; + if (!qparam) qparam = ""; + if (hio_svc_fcgic_writeparam(fcgi->peer, "QUERY_STRING", 12, qparam, hio_count_bcstr(qparam)) <= -1) goto oops; if (hio_htre_getreqcontentlen(req, &content_length) == 0) { @@ -753,7 +837,8 @@ static int write_params (fcgi_t* fcgi, hio_dev_sck_t* csck, hio_htre_t* req, con len = hio_skadtobcstr (hio, &csck->remoteaddr, tmp, HIO_COUNTOF(tmp), HIO_SKAD_TO_BCSTR_PORT); if (hio_svc_fcgic_writeparam(fcgi->peer, "REMOTE_PORT", 11, tmp, len) <= -1) goto oops; - //hio_htre_walkheaders (req,) + hio_htre_walkheaders (req, peer_capture_request_header, fcgi); + /* [NOTE] trailers are not available when this cgi resource is started. let's not call hio_htre_walktrailers() */ hio_freemem (hio, actual_script); return 0; @@ -882,10 +967,8 @@ static void unbind_task_from_peer (fcgi_t* fcgi, int rcdown) hio_svc_fcgic_untie (fcgi->peer); fcgi->peer = HIO_NULL; n++; - } - if (rcdown) { while (n > 0) @@ -981,6 +1064,7 @@ static int setup_for_content_length(fcgi_t* fcgi, hio_htre_t* req) } #endif +#if 0 /* this may change later if Content-Length is included in the fcgi output */ if (req->flags & HIO_HTRE_ATTR_KEEPALIVE) { @@ -989,6 +1073,7 @@ static int setup_for_content_length(fcgi_t* fcgi, hio_htre_t* req) /* the mode still can get switched to FCGI_RES_MODE_LENGTH if the fcgi script emits Content-Length */ } else +#endif { fcgi->keep_alive = 0; fcgi->res_mode_to_cli = FCGI_RES_MODE_CLOSE; @@ -996,6 +1081,7 @@ static int setup_for_content_length(fcgi_t* fcgi, hio_htre_t* req) return 0; } + int hio_svc_htts_dofcgi (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* req, const hio_skad_t* fcgis_addr, const hio_bch_t* docroot, const hio_bch_t* script, int options) { hio_t* hio = htts->hio; diff --git a/lib/http-prv.h b/lib/http-prv.h index 348a314..7ba383d 100644 --- a/lib/http-prv.h +++ b/lib/http-prv.h @@ -77,6 +77,9 @@ struct hio_svc_htts_t hio_bch_t* server_name; hio_bch_t server_name_buf[64]; + + int fcgic_tmout_set; + hio_svc_fcgic_tmout_t fcgic_tmout; }; struct hio_svc_httc_t diff --git a/lib/http-svr.c b/lib/http-svr.c index 3eb6035..dfcd1e0 100644 --- a/lib/http-svr.c +++ b/lib/http-svr.c @@ -330,7 +330,8 @@ static void halt_idle_clients (hio_t* hio, const hio_ntime_t* now, hio_tmrjob_t* } /* ------------------------------------------------------------------------ */ -hio_svc_htts_t* hio_svc_htts_start (hio_t* hio, hio_oow_t xtnsize, hio_dev_sck_bind_t* binds, hio_oow_t nbinds, hio_svc_htts_proc_req_t proc_req) + +hio_svc_htts_t* hio_svc_htts_start (hio_t* hio, hio_oow_t xtnsize, hio_dev_sck_bind_t* binds, hio_oow_t nbinds, hio_svc_htts_proc_req_t proc_req, const hio_svc_fcgic_tmout_t* fcgic_tmout) { hio_svc_htts_t* htts = HIO_NULL; union @@ -357,6 +358,12 @@ hio_svc_htts_t* hio_svc_htts_start (hio_t* hio, hio_oow_t xtnsize, hio_dev_sck_b htts->proc_req = proc_req; htts->idle_tmridx = HIO_TMRIDX_INVALID; + if (fcgic_tmout) + { + htts->fcgic_tmout_set = 1; + htts->fcgic_tmout = *fcgic_tmout; + } + htts->l.sck = (hio_dev_sck_t**)hio_callocmem(hio, HIO_SIZEOF(*htts->l.sck) * nbinds); if (HIO_UNLIKELY(!htts->l.sck)) goto oops; htts->l.count = nbinds; @@ -468,7 +475,8 @@ hio_svc_htts_t* hio_svc_htts_start (hio_t* hio, hio_oow_t xtnsize, hio_dev_sck_b HIO_SVC_HTTS_CLIL_INIT (&htts->cli); HIO_SVC_HTTS_TASKL_INIT (&htts->task); - htts->fcgic = hio_svc_fcgic_start(hio, HIO_NULL); /* TODO: set timeout properly */ + htts->fcgic = hio_svc_fcgic_start(htts->hio, (htts->fcgic_tmout_set? &htts->fcgic_tmout: HIO_NULL)); + if (HIO_UNLIKELY(!htts->fcgic)) { /* TODO: only warning ... */ @@ -676,9 +684,6 @@ void hio_svc_htts_task_kill (hio_svc_htts_task_t* task) HIO_DEBUG2 (hio, "HTTS(%p) - destroyed task %p\n", htts, task); } -/* ----------------------------------------------------------------- */ - - /* ----------------------------------------------------------------- */ int hio_svc_htts_doproxy (hio_svc_htts_t* htts, hio_dev_sck_t* csck, hio_htre_t* req, const hio_bch_t* upstream)