2020-05-25 08:04:30 +00:00
/*
Copyright ( c ) 2016 - 2020 Chung , Hyung - Hwan . All rights reserved .
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
documentation and / or other materials provided with the distribution .
THIS SOFTWARE IS PROVIDED BY THE AUTHOR " AS IS " AND ANY EXPRESS OR
2022-06-11 05:32:01 +00:00
IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
2020-05-25 08:04:30 +00:00
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "http-prv.h"
2021-07-22 07:30:20 +00:00
# include <hio-pro.h>
# include <hio-fmt.h>
# include <hio-chr.h>
2020-05-25 08:04:30 +00:00
# include <unistd.h> /* TODO: move file operations to sys-file.XXX */
# include <fcntl.h>
# include <sys/stat.h>
# include <stdlib.h> /* setenv, clearenv */
2022-06-22 13:14:35 +00:00
# if defined(HAVE_CRT_EXTERNS_H)
# include <crt_externs.h> /* _NSGetEnviron */
# endif
2020-05-25 08:04:30 +00:00
# define CGI_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH
2020-11-16 16:52:49 +00:00
# define CGI_PENDING_IO_THRESHOLD 5
2020-05-25 08:04:30 +00:00
2020-11-16 16:52:49 +00:00
# define CGI_OVER_READ_FROM_CLIENT (1 << 0)
# define CGI_OVER_READ_FROM_PEER (1 << 1)
# define CGI_OVER_WRITE_TO_CLIENT (1 << 2)
# define CGI_OVER_WRITE_TO_PEER (1 << 3)
# define CGI_OVER_ALL (CGI_OVER_READ_FROM_CLIENT | CGI_OVER_READ_FROM_PEER | CGI_OVER_WRITE_TO_CLIENT | CGI_OVER_WRITE_TO_PEER)
2020-05-25 08:04:30 +00:00
2020-11-16 16:52:49 +00:00
struct cgi_t
2020-05-25 08:04:30 +00:00
{
2023-01-11 15:41:01 +00:00
HIO_SVC_HTTS_TASK_HEADER ;
2020-05-25 08:04:30 +00:00
2023-03-04 15:55:15 +00:00
hio_svc_htts_task_on_kill_t on_kill ; /* user-provided on_kill callback */
2022-10-09 16:41:07 +00:00
int options ;
2023-03-19 18:01:35 +00:00
hio_oow_t peer_pending_writes ;
2021-07-22 07:30:20 +00:00
hio_dev_pro_t * peer ;
hio_htrd_t * peer_htrd ;
2023-01-14 14:54:54 +00:00
2020-11-16 16:52:49 +00:00
unsigned int over : 4 ; /* must be large enough to accomodate CGI_OVER_ALL */
2020-05-26 14:58:55 +00:00
unsigned int client_htrd_recbs_changed : 1 ;
2020-05-25 08:04:30 +00:00
2021-07-22 07:30:20 +00:00
hio_dev_sck_on_read_t client_org_on_read ;
hio_dev_sck_on_write_t client_org_on_write ;
hio_dev_sck_on_disconnect_t client_org_on_disconnect ;
hio_htrd_recbs_t client_htrd_org_recbs ;
2020-05-25 08:04:30 +00:00
} ;
2020-11-16 16:52:49 +00:00
typedef struct cgi_t cgi_t ;
2020-05-25 08:04:30 +00:00
struct cgi_peer_xtn_t
{
2022-08-31 23:01:32 +00:00
cgi_t * cgi ; /* back pointer to the cgi object */
2020-05-25 08:04:30 +00:00
} ;
typedef struct cgi_peer_xtn_t cgi_peer_xtn_t ;
2023-03-19 18:01:35 +00:00
static void unbind_task_from_client ( cgi_t * cgi , int rcdown ) ;
static void unbind_task_from_peer ( cgi_t * cgi , int rcdown ) ;
2020-11-16 16:52:49 +00:00
static void cgi_halt_participating_devices ( cgi_t * cgi )
2020-05-25 08:04:30 +00:00
{
2023-03-05 18:27:42 +00:00
HIO_DEBUG5 ( cgi - > htts - > hio , " HTTS(%p) - cgi(t=%p,c=%p(%d),p=%p) Halting participating devices \n " , cgi - > htts , cgi , cgi - > task_csck , ( cgi - > task_csck ? cgi - > task_csck - > hnd : - 1 ) , cgi - > peer ) ;
2020-05-25 08:04:30 +00:00
2023-03-05 18:27:42 +00:00
if ( cgi - > task_csck ) hio_dev_sck_halt ( cgi - > task_csck ) ;
2020-05-25 08:04:30 +00:00
/* check for peer as it may not have been started */
2021-07-22 07:30:20 +00:00
if ( cgi - > peer ) hio_dev_pro_halt ( cgi - > peer ) ;
2020-05-25 08:04:30 +00:00
}
2021-07-22 07:30:20 +00:00
static int cgi_write_to_peer ( cgi_t * cgi , const void * data , hio_iolen_t dlen )
2020-05-25 08:04:30 +00:00
{
2023-01-14 14:54:54 +00:00
if ( cgi - > peer )
2020-05-25 08:04:30 +00:00
{
2023-03-19 18:01:35 +00:00
cgi - > peer_pending_writes + + ;
2023-01-14 14:54:54 +00:00
if ( hio_dev_pro_write ( cgi - > peer , data , dlen , HIO_NULL ) < = - 1 )
{
2023-03-19 18:01:35 +00:00
cgi - > peer_pending_writes - - ;
2023-01-14 14:54:54 +00:00
return - 1 ;
}
2020-05-25 08:04:30 +00:00
2023-01-14 14:54:54 +00:00
/* TODO: check if it's already finished or something.. */
2023-03-19 18:01:35 +00:00
if ( cgi - > peer_pending_writes > CGI_PENDING_IO_THRESHOLD )
2023-01-14 14:54:54 +00:00
{
/* suspend input watching */
2023-03-05 18:27:42 +00:00
if ( cgi - > task_csck & & hio_dev_sck_read ( cgi - > task_csck , 0 ) < = - 1 ) return - 1 ;
2023-01-14 14:54:54 +00:00
}
2020-05-25 08:04:30 +00:00
}
return 0 ;
}
2021-07-22 07:30:20 +00:00
static HIO_INLINE void cgi_mark_over ( cgi_t * cgi , int over_bits )
2020-05-25 08:04:30 +00:00
{
2023-01-14 14:54:54 +00:00
hio_svc_htts_t * htts = cgi - > htts ;
hio_t * hio = htts - > hio ;
2020-05-25 08:04:30 +00:00
unsigned int old_over ;
2020-11-16 16:52:49 +00:00
old_over = cgi - > over ;
cgi - > over | = over_bits ;
2020-05-25 08:04:30 +00:00
2023-03-05 18:27:42 +00:00
HIO_DEBUG8 ( hio , " HTTS(%p) - cgi(t=%p,c=%p[%d],p=%p) - old_over=%x | new-bits=%x => over=%x \n " , cgi - > htts , cgi , cgi - > task_client , ( cgi - > task_csck ? cgi - > task_csck - > hnd : - 1 ) , cgi - > peer , ( int ) old_over , ( int ) over_bits , ( int ) cgi - > over ) ;
2020-05-25 08:04:30 +00:00
2020-11-16 16:52:49 +00:00
if ( ! ( old_over & CGI_OVER_READ_FROM_CLIENT ) & & ( cgi - > over & CGI_OVER_READ_FROM_CLIENT ) )
2020-05-25 08:04:30 +00:00
{
2023-03-05 18:27:42 +00:00
if ( cgi - > task_csck & & hio_dev_sck_read ( cgi - > task_csck , 0 ) < = - 1 )
2020-05-25 08:04:30 +00:00
{
2023-03-05 18:27:42 +00:00
HIO_DEBUG5 ( hio , " HTTS(%p) - cgi(t=%p,c=%p[%d],p=%p) - halting client for failure to disable input watching \n " , cgi - > htts , cgi , cgi - > task_client , ( cgi - > task_csck ? cgi - > task_csck - > hnd : - 1 ) , cgi - > peer ) ;
hio_dev_sck_halt ( cgi - > task_csck ) ;
2020-05-25 08:04:30 +00:00
}
}
2020-11-16 16:52:49 +00:00
if ( ! ( old_over & CGI_OVER_READ_FROM_PEER ) & & ( cgi - > over & CGI_OVER_READ_FROM_PEER ) )
2020-05-25 08:04:30 +00:00
{
2023-01-11 14:59:41 +00:00
if ( cgi - > peer & & hio_dev_pro_read ( cgi - > peer , HIO_DEV_PRO_OUT , 0 ) < = - 1 )
2020-05-25 08:04:30 +00:00
{
2023-03-05 18:27:42 +00:00
HIO_DEBUG5 ( hio , " HTTS(%p) - cgi(t=%p,c=%p[%d],p=%p) - halting peer for failure to disable input watching \n " , cgi - > htts , cgi , cgi - > task_client , ( cgi - > task_csck ? cgi - > task_csck - > hnd : - 1 ) , cgi - > peer ) ;
2021-07-22 07:30:20 +00:00
hio_dev_pro_halt ( cgi - > peer ) ;
2020-05-25 08:04:30 +00:00
}
}
2020-11-16 16:52:49 +00:00
if ( old_over ! = CGI_OVER_ALL & & cgi - > over = = CGI_OVER_ALL )
2020-05-25 08:04:30 +00:00
{
/* ready to stop */
2023-01-11 14:59:41 +00:00
if ( cgi - > peer )
2020-05-25 08:04:30 +00:00
{
2023-03-05 18:27:42 +00:00
HIO_DEBUG5 ( hio , " HTTS(%p) - cgi(t=%p,c=%p[%d],p=%p) - halting unneeded peer \n " , cgi - > htts , cgi , cgi - > task_client , ( cgi - > task_csck ? cgi - > task_csck - > hnd : - 1 ) , cgi - > peer ) ;
2021-07-22 07:30:20 +00:00
hio_dev_pro_halt ( cgi - > peer ) ;
2020-05-25 08:04:30 +00:00
}
2023-03-05 18:27:42 +00:00
if ( cgi - > task_csck )
2020-05-25 08:04:30 +00:00
{
2023-03-04 15:55:15 +00:00
HIO_ASSERT ( hio , cgi - > task_client ! = HIO_NULL ) ;
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
if ( cgi - > task_keep_client_alive )
2023-01-14 14:54:54 +00:00
{
2023-03-19 18:01:35 +00:00
HIO_DEBUG5 ( hio , " HTTS(%p) - cgi(t=%p,c=%p[%d],p=%p) - keeping client alive \n " , cgi - > htts , cgi , cgi - > task_client , ( cgi - > task_csck ? cgi - > task_csck - > hnd : - 1 ) , cgi - > peer ) ;
2023-03-04 15:55:15 +00:00
HIO_ASSERT ( cgi - > htts - > hio , cgi - > task_client - > task = = ( hio_svc_htts_task_t * ) cgi ) ;
2023-03-19 18:01:35 +00:00
unbind_task_from_client ( cgi , 1 ) ;
2023-01-14 14:54:54 +00:00
/* cgi must not be accessed from here down as it could have been destroyed */
}
else
{
2023-03-19 18:01:35 +00:00
HIO_DEBUG5 ( hio , " HTTS(%p) - cgi(t=%p,c=%p[%d],p=%p) - halting client for no keep-alive \n " , cgi - > htts , cgi , cgi - > task_client , ( cgi - > task_csck ? cgi - > task_csck - > hnd : - 1 ) , cgi - > peer ) ;
2023-03-05 18:27:42 +00:00
hio_dev_sck_shutdown ( cgi - > task_csck , HIO_DEV_SCK_SHUTDOWN_WRITE ) ;
hio_dev_sck_halt ( cgi - > task_csck ) ;
2023-01-14 14:54:54 +00:00
}
2020-05-25 08:04:30 +00:00
}
}
}
2023-01-11 15:41:01 +00:00
static void cgi_on_kill ( hio_svc_htts_task_t * task )
2020-05-25 08:04:30 +00:00
{
2023-01-11 15:41:01 +00:00
cgi_t * cgi = ( cgi_t * ) task ;
2021-07-22 07:30:20 +00:00
hio_t * hio = cgi - > htts - > hio ;
2020-07-08 05:24:40 +00:00
2023-03-05 18:27:42 +00:00
HIO_DEBUG5 ( hio , " HTTS(%p) - cgi(t=%p,c=%p[%d],p=%p) - killing the task \n " , cgi - > htts , cgi , cgi - > task_client , ( cgi - > task_csck ? cgi - > task_csck - > hnd : - 1 ) , cgi - > peer ) ;
2023-03-04 15:55:15 +00:00
if ( cgi - > on_kill ) cgi - > on_kill ( task ) ;
2020-07-08 05:24:40 +00:00
2023-03-19 18:01:35 +00:00
/* [NOTE]
* 1. if hio_svc_htts_task_kill ( ) is called , cgi - > peer , cgi - > peer_htrd , cgi - > task_csck ,
* cgi - > task_client may not not null .
* 2. this callback function doesn ' t decrement the reference count on cgi because
* it is the task destruction callback . ( passing 0 to unbind_task_from_peer / client )
*/
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
unbind_task_from_peer ( cgi , 0 ) ;
2020-05-25 08:04:30 +00:00
2023-03-05 18:27:42 +00:00
if ( cgi - > task_csck )
2020-05-25 08:04:30 +00:00
{
2023-03-04 15:55:15 +00:00
HIO_ASSERT ( hio , cgi - > task_client ! = HIO_NULL ) ;
2023-03-19 18:01:35 +00:00
unbind_task_from_client ( cgi , 0 ) ;
2020-05-25 08:04:30 +00:00
}
2023-01-14 14:54:54 +00:00
if ( cgi - > task_next ) HIO_SVC_HTTS_TASKL_UNLINK_TASK ( cgi ) ; /* detach from the htts service only if it's attached */
2023-03-05 18:27:42 +00:00
HIO_DEBUG5 ( hio , " HTTS(%p) - cgi(t=%p,c=%p[%d],p=%p) - killed the task \n " , cgi - > htts , cgi , cgi - > task_client , ( cgi - > task_csck ? cgi - > task_csck - > hnd : - 1 ) , cgi - > peer ) ;
2020-05-25 08:04:30 +00:00
}
2023-01-14 14:54:54 +00:00
static void cgi_peer_on_close ( hio_dev_pro_t * pro , hio_dev_pro_sid_t sid )
2020-05-25 08:04:30 +00:00
{
2021-07-22 07:30:20 +00:00
hio_t * hio = pro - > hio ;
2022-09-05 23:19:08 +00:00
cgi_peer_xtn_t * peer_xtn = hio_dev_pro_getxtn ( pro ) ;
cgi_t * cgi = peer_xtn - > cgi ;
2020-05-25 08:04:30 +00:00
2020-11-16 16:52:49 +00:00
if ( ! cgi ) return ; /* cgi state already gone */
2020-05-25 08:04:30 +00:00
switch ( sid )
{
2021-07-22 07:30:20 +00:00
case HIO_DEV_PRO_MASTER :
2023-01-14 15:59:43 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - peer %p(pid=%d) closing master \n " , cgi - > htts , pro , ( int ) pro - > child_pid ) ;
2023-03-19 18:01:35 +00:00
/* reset cgi->peer before calling unbind_task_from_peer() because this is the peer close callback */
cgi - > peer = HIO_NULL ;
unbind_task_from_peer ( cgi , 1 ) ;
2020-05-25 08:04:30 +00:00
break ;
2021-07-22 07:30:20 +00:00
case HIO_DEV_PRO_OUT :
2023-03-19 18:01:35 +00:00
/* the output from peer closing. input to the client must be ended */
2021-07-22 07:30:20 +00:00
HIO_ASSERT ( hio , cgi - > peer = = pro ) ;
2023-01-14 15:59:43 +00:00
HIO_DEBUG4 ( hio , " HTTS(%p) - peer %p(pid=%d) closing slave[%d] \n " , cgi - > htts , pro , ( int ) pro - > child_pid , sid ) ;
2020-05-25 08:04:30 +00:00
2020-11-16 16:52:49 +00:00
if ( ! ( cgi - > over & CGI_OVER_READ_FROM_PEER ) )
2020-05-25 08:04:30 +00:00
{
2023-03-19 18:01:35 +00:00
if ( hio_svc_htts_task_endbody ( cgi ) < = - 1 )
2020-11-16 16:52:49 +00:00
cgi_halt_participating_devices ( cgi ) ;
2020-05-25 08:04:30 +00:00
else
2020-11-16 16:52:49 +00:00
cgi_mark_over ( cgi , CGI_OVER_READ_FROM_PEER ) ;
2020-05-25 08:04:30 +00:00
}
break ;
2021-07-22 07:30:20 +00:00
case HIO_DEV_PRO_IN :
2023-01-14 15:59:43 +00:00
HIO_DEBUG4 ( hio , " HTTS(%p) - peer %p(pid=%d) closing slave[%d] \n " , cgi - > htts , pro , ( int ) pro - > child_pid , sid ) ;
2020-11-16 16:52:49 +00:00
cgi_mark_over ( cgi , CGI_OVER_WRITE_TO_PEER ) ;
2020-05-25 08:04:30 +00:00
break ;
2021-07-22 07:30:20 +00:00
case HIO_DEV_PRO_ERR :
2020-05-25 08:04:30 +00:00
default :
2023-01-14 15:59:43 +00:00
HIO_DEBUG4 ( hio , " HTTS(%p) - peer %p(pid=%d) closing slave[%d] \n " , cgi - > htts , pro , ( int ) pro - > child_pid , sid ) ;
2020-05-25 08:04:30 +00:00
/* do nothing */
break ;
}
}
2023-01-14 14:54:54 +00:00
static int cgi_peer_on_read ( hio_dev_pro_t * pro , hio_dev_pro_sid_t sid , const void * data , hio_iolen_t dlen )
2020-05-25 08:04:30 +00:00
{
2021-07-22 07:30:20 +00:00
hio_t * hio = pro - > hio ;
2022-08-31 23:01:32 +00:00
cgi_peer_xtn_t * peer = hio_dev_pro_getxtn ( pro ) ;
cgi_t * cgi = peer - > cgi ;
2020-05-25 08:04:30 +00:00
2021-07-22 07:30:20 +00:00
HIO_ASSERT ( hio , sid = = HIO_DEV_PRO_OUT ) ; /* since HIO_DEV_PRO_ERRTONUL is used, there should be no input from HIO_DEV_PRO_ERR */
HIO_ASSERT ( hio , cgi ! = HIO_NULL ) ;
2020-05-25 08:04:30 +00:00
if ( dlen < = - 1 )
{
2023-01-14 15:59:43 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - read error from peer %p(pid=%u) \n " , cgi - > htts , pro , ( unsigned int ) pro - > child_pid ) ;
2020-05-25 08:04:30 +00:00
goto oops ;
}
if ( dlen = = 0 )
{
2023-01-14 15:59:43 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - EOF from peer %p(pid=%u) \n " , cgi - > htts , pro , ( unsigned int ) pro - > child_pid ) ;
2020-05-25 08:04:30 +00:00
2020-11-16 16:52:49 +00:00
if ( ! ( cgi - > over & CGI_OVER_READ_FROM_PEER ) )
2020-05-25 08:04:30 +00:00
{
2022-06-25 16:00:28 +00:00
int n ;
/* the cgi script could be misbehaving.
2020-05-25 08:04:30 +00:00
* it still has to read more but EOF is read .
2022-08-31 23:01:32 +00:00
* otherwise peer_htrd_poke ( ) should have been called */
2023-03-19 18:01:35 +00:00
n = hio_svc_htts_task_endbody ( cgi ) ;
2020-11-16 16:52:49 +00:00
cgi_mark_over ( cgi , CGI_OVER_READ_FROM_PEER ) ;
2022-06-25 16:00:28 +00:00
if ( n < = - 1 ) goto oops ;
2020-05-25 08:04:30 +00:00
}
}
else
{
2021-07-22 07:30:20 +00:00
hio_oow_t rem ;
2020-05-25 08:04:30 +00:00
2021-07-22 07:30:20 +00:00
HIO_ASSERT ( hio , ! ( cgi - > over & CGI_OVER_READ_FROM_PEER ) ) ;
2020-05-25 08:04:30 +00:00
2023-01-11 14:59:41 +00:00
if ( hio_htrd_feed ( cgi - > peer_htrd , data , dlen , & rem ) < = - 1 )
2020-05-25 08:04:30 +00:00
{
2022-06-25 16:00:28 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - unable to feed peer htrd - peer %p(pid=%u) \n " , cgi - > htts , pro , ( unsigned int ) pro - > child_pid ) ;
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
if ( ! cgi - > task_res_started & & ! ( cgi - > over & CGI_OVER_WRITE_TO_CLIENT ) )
2020-05-25 08:04:30 +00:00
{
2023-03-19 18:01:35 +00:00
hio_svc_htts_task_sendfinalres ( cgi , HIO_HTTP_STATUS_BAD_GATEWAY , HIO_NULL , HIO_NULL , 1 ) ; /* don't care about error because it jumps to oops below anyway */
2020-05-25 08:04:30 +00:00
}
2023-01-11 14:59:41 +00:00
goto oops ;
2020-05-25 08:04:30 +00:00
}
2023-01-11 14:59:41 +00:00
if ( rem > 0 )
2020-05-25 08:04:30 +00:00
{
/* If the script specifies Content-Length and produces longer data, it will come here */
}
}
return 0 ;
oops :
2020-11-16 16:52:49 +00:00
cgi_halt_participating_devices ( cgi ) ;
2020-05-25 08:04:30 +00:00
return 0 ;
}
2023-02-20 12:01:10 +00:00
static int cgi_peer_on_write ( hio_dev_pro_t * pro , hio_iolen_t wrlen , void * wrctx )
{
hio_t * hio = pro - > hio ;
cgi_peer_xtn_t * peer = hio_dev_pro_getxtn ( pro ) ;
cgi_t * cgi = peer - > cgi ;
2023-03-19 18:01:35 +00:00
if ( ! cgi ) return 0 ; /* there is nothing i can do. the cgi is being cleared or has been cleared already. */
2023-02-20 12:01:10 +00:00
HIO_ASSERT ( hio , cgi - > peer = = pro ) ;
if ( wrlen < = - 1 )
{
HIO_DEBUG3 ( hio , " HTTS(%p) - unable to write to peer %p(pid=%u) \n " , cgi - > htts , pro , ( int ) pro - > child_pid ) ;
goto oops ;
}
else if ( wrlen = = 0 )
{
/* indicated EOF */
2023-03-19 18:01:35 +00:00
/* do nothing here as i didn't increment peer_pending_writes when making the write request */
2023-02-20 12:01:10 +00:00
2023-03-19 18:01:35 +00:00
cgi - > peer_pending_writes - - ;
HIO_ASSERT ( hio , cgi - > peer_pending_writes = = 0 ) ;
2023-02-20 12:01:10 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - indicated EOF to peer %p(pid=%u) \n " , cgi - > 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_mark_over ( cgi , CGI_OVER_WRITE_TO_PEER ) ;
}
else
{
2023-03-19 18:01:35 +00:00
HIO_ASSERT ( hio , cgi - > peer_pending_writes > 0 ) ;
2023-02-20 12:01:10 +00:00
2023-03-19 18:01:35 +00:00
cgi - > peer_pending_writes - - ;
if ( cgi - > peer_pending_writes = = CGI_PENDING_IO_THRESHOLD )
2023-02-20 12:01:10 +00:00
{
if ( ! ( cgi - > over & CGI_OVER_READ_FROM_CLIENT ) & &
2023-03-05 18:27:42 +00:00
hio_dev_sck_read ( cgi - > task_csck , 1 ) < = - 1 ) goto oops ;
2023-02-20 12:01:10 +00:00
}
2023-03-19 18:01:35 +00:00
if ( ( cgi - > over & CGI_OVER_READ_FROM_CLIENT ) & & cgi - > peer_pending_writes < = 0 )
2023-02-20 12:01:10 +00:00
{
cgi_mark_over ( cgi , CGI_OVER_WRITE_TO_PEER ) ;
}
}
return 0 ;
oops :
cgi_halt_participating_devices ( cgi ) ;
return 0 ;
}
2022-08-31 23:01:32 +00:00
static int peer_capture_response_header ( hio_htre_t * req , const hio_bch_t * key , const hio_htre_hdrval_t * val , void * ctx )
2020-05-25 08:04:30 +00:00
{
2023-03-10 17:32:33 +00:00
return hio_svc_htts_task_addreshdrs ( ( cgi_t * ) ctx , key , val ) ;
2020-05-25 08:04:30 +00:00
}
2022-08-31 23:01:32 +00:00
static int peer_htrd_peek ( hio_htrd_t * htrd , hio_htre_t * req )
2020-05-25 08:04:30 +00:00
{
2022-08-31 23:01:32 +00:00
cgi_peer_xtn_t * peer = hio_htrd_getxtn ( htrd ) ;
cgi_t * cgi = peer - > cgi ;
2023-03-04 15:55:15 +00:00
hio_svc_htts_cli_t * cli = cgi - > task_client ;
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
if ( HIO_LIKELY ( cli ) )
2020-05-25 08:04:30 +00:00
{
2023-03-19 18:01:35 +00:00
int status_code = HIO_HTTP_STATUS_OK ;
const hio_bch_t * status_desc = HIO_NULL ;
int chunked ;
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
if ( req - > attr . status ) hio_parse_http_status_header_value ( req - > attr . status , & status_code , & status_desc ) ;
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
chunked = cgi - > task_keep_client_alive & & ! req - > attr . content_length ;
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
if ( hio_svc_htts_task_startreshdr ( cgi , status_code , status_desc , chunked ) < = - 1 | |
hio_htre_walkheaders ( req , peer_capture_response_header , cgi ) < = - 1 | |
hio_svc_htts_task_endreshdr ( cgi ) < = - 1 ) return - 1 ;
}
2020-05-25 08:04:30 +00:00
2023-03-18 20:04:32 +00:00
return 0 ;
2020-05-25 08:04:30 +00:00
}
2022-08-31 23:01:32 +00:00
static int peer_htrd_poke ( hio_htrd_t * htrd , hio_htre_t * req )
2020-05-25 08:04:30 +00:00
{
2023-03-18 20:04:32 +00:00
/* peer response got completed */
2022-08-31 23:01:32 +00:00
cgi_peer_xtn_t * peer = hio_htrd_getxtn ( htrd ) ;
cgi_t * cgi = peer - > cgi ;
2023-03-19 18:01:35 +00:00
int n ;
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
n = hio_svc_htts_task_endbody ( cgi ) ;
2020-11-16 16:52:49 +00:00
cgi_mark_over ( cgi , CGI_OVER_READ_FROM_PEER ) ;
2023-03-19 18:01:35 +00:00
return n ;
2020-05-25 08:04:30 +00:00
}
2022-08-31 23:01:32 +00:00
static int peer_htrd_push_content ( hio_htrd_t * htrd , hio_htre_t * req , const hio_bch_t * data , hio_oow_t dlen )
2020-05-25 08:04:30 +00:00
{
2022-08-31 23:01:32 +00:00
cgi_peer_xtn_t * peer = hio_htrd_getxtn ( htrd ) ;
cgi_t * cgi = peer - > cgi ;
2023-03-19 18:01:35 +00:00
int n ;
2020-05-25 08:04:30 +00:00
2023-01-14 15:59:43 +00:00
HIO_ASSERT ( cgi - > htts - > hio , htrd = = cgi - > peer_htrd ) ;
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
n = hio_svc_htts_task_addresbody ( cgi , data , dlen ) ;
if ( cgi - > task_res_pending_writes > CGI_PENDING_IO_THRESHOLD )
2020-05-25 08:04:30 +00:00
{
2023-03-19 18:01:35 +00:00
if ( hio_dev_pro_read ( cgi - > peer , HIO_DEV_PRO_OUT , 0 ) < = - 1 ) return - 1 ;
2020-05-25 08:04:30 +00:00
}
2023-03-19 18:01:35 +00:00
return n ;
2020-05-25 08:04:30 +00:00
}
2022-08-31 23:01:32 +00:00
static hio_htrd_recbs_t peer_htrd_recbs =
2020-05-25 08:04:30 +00:00
{
2022-08-31 23:01:32 +00:00
peer_htrd_peek ,
peer_htrd_poke ,
peer_htrd_push_content
2020-05-25 08:04:30 +00:00
} ;
2021-07-22 07:30:20 +00:00
static int cgi_client_htrd_poke ( hio_htrd_t * htrd , hio_htre_t * req )
2020-05-25 08:04:30 +00:00
{
/* client request got completed */
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_htrd_xtn_t * htrdxtn = ( hio_svc_htts_cli_htrd_xtn_t * ) hio_htrd_getxtn ( htrd ) ;
hio_dev_sck_t * sck = htrdxtn - > sck ;
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( sck ) ;
2023-01-11 15:41:01 +00:00
cgi_t * cgi = ( cgi_t * ) cli - > task ;
2020-05-25 08:04:30 +00:00
/* indicate EOF to the client peer */
2021-07-22 07:30:20 +00:00
if ( cgi_write_to_peer ( cgi , HIO_NULL , 0 ) < = - 1 ) return - 1 ;
2020-05-25 08:04:30 +00:00
2020-11-16 16:52:49 +00:00
cgi_mark_over ( cgi , CGI_OVER_READ_FROM_CLIENT ) ;
2020-05-25 08:04:30 +00:00
return 0 ;
}
2021-07-22 07:30:20 +00:00
static int cgi_client_htrd_push_content ( hio_htrd_t * htrd , hio_htre_t * req , const hio_bch_t * data , hio_oow_t dlen )
2020-05-25 08:04:30 +00:00
{
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_htrd_xtn_t * htrdxtn = ( hio_svc_htts_cli_htrd_xtn_t * ) hio_htrd_getxtn ( htrd ) ;
hio_dev_sck_t * sck = htrdxtn - > sck ;
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( sck ) ;
2023-01-11 15:41:01 +00:00
cgi_t * cgi = ( cgi_t * ) cli - > task ;
2020-05-25 08:04:30 +00:00
2021-07-22 07:30:20 +00:00
HIO_ASSERT ( sck - > hio , cli - > sck = = sck ) ;
2020-11-16 16:52:49 +00:00
return cgi_write_to_peer ( cgi , data , dlen ) ;
2020-05-25 08:04:30 +00:00
}
2021-07-22 07:30:20 +00:00
static hio_htrd_recbs_t cgi_client_htrd_recbs =
2020-05-25 08:04:30 +00:00
{
2022-08-31 23:01:32 +00:00
HIO_NULL , /* this shall be set to an actual peer handler before hio_htrd_setrecbs() */
2020-05-25 08:04:30 +00:00
cgi_client_htrd_poke ,
cgi_client_htrd_push_content
} ;
2021-07-22 07:30:20 +00:00
static void cgi_client_on_disconnect ( hio_dev_sck_t * sck )
2020-05-25 08:04:30 +00:00
{
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( sck ) ;
2023-01-14 14:54:54 +00:00
hio_svc_htts_t * htts = cli - > htts ;
2023-01-11 15:41:01 +00:00
cgi_t * cgi = ( cgi_t * ) cli - > task ;
2023-01-14 14:54:54 +00:00
hio_t * hio = sck - > hio ;
2023-03-05 18:27:42 +00:00
HIO_ASSERT ( hio , sck = = cgi - > task_csck ) ;
2023-01-14 14:54:54 +00:00
HIO_DEBUG4 ( hio , " HTTS(%p) - cgi(t=%p,c=%p,csck=%p) - client socket disconnect notified \n " , htts , cgi , cli , sck ) ;
2023-03-19 18:01:35 +00:00
if ( cgi )
2023-01-14 14:54:54 +00:00
{
2023-03-19 18:01:35 +00:00
HIO_SVC_HTTS_TASK_RCUP ( cgi ) ;
/* detach the task from the client and the client socket */
unbind_task_from_client ( cgi , 1 ) ;
/* call the parent handler*/
/*if (fcgi->client_org_on_disconnect) fcgi->client_org_on_disconnect (sck);*/
if ( sck - > on_disconnect ) sck - > on_disconnect ( sck ) ; /* restored to the orginal parent handelr in unbind_task_from_client() */
HIO_SVC_HTTS_TASK_RCDOWN ( cgi ) ;
2023-01-14 14:54:54 +00:00
}
HIO_DEBUG4 ( hio , " HTTS(%p) - cgi(t=%p,c=%p,csck=%p) - client socket disconnect handled \n " , htts , cgi , cli , sck ) ;
/* Note: after this callback, the actual device pointed to by 'sck' will be freed in the main loop. */
2020-05-25 08:04:30 +00:00
}
2021-07-22 07:30:20 +00:00
static int cgi_client_on_read ( hio_dev_sck_t * sck , const void * buf , hio_iolen_t len , const hio_skad_t * srcaddr )
2020-05-25 08:04:30 +00:00
{
2021-07-22 07:30:20 +00:00
hio_t * hio = sck - > hio ;
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( sck ) ;
2023-01-11 15:41:01 +00:00
cgi_t * cgi = ( cgi_t * ) cli - > task ;
2023-03-19 18:01:35 +00:00
int n ;
2020-05-25 08:04:30 +00:00
2021-07-22 07:30:20 +00:00
HIO_ASSERT ( hio , sck = = cli - > sck ) ;
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
n = cgi - > client_org_on_read ? cgi - > client_org_on_read ( sck , buf , len , srcaddr ) : 0 ;
2020-05-25 08:04:30 +00:00
if ( len < = - 1 )
{
/* read error */
2023-03-18 20:04:32 +00:00
HIO_DEBUG3 ( cli - > htts - > hio , " HTTS(%p) - read error on client %p(%d) \n " , cgi - > htts , sck , ( int ) sck - > hnd ) ;
2020-05-25 08:04:30 +00:00
goto oops ;
}
if ( len = = 0 )
{
/* EOF on the client side. arrange to close */
2023-01-14 15:59:43 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - EOF from client %p(hnd=%d) \n " , cgi - > htts , sck , ( int ) sck - > hnd ) ;
2020-05-25 08:04:30 +00:00
2020-11-16 16:52:49 +00:00
if ( ! ( cgi - > over & CGI_OVER_READ_FROM_CLIENT ) ) /* if this is true, EOF is received without cgi_client_htrd_poke() */
2020-05-25 08:04:30 +00:00
{
2023-03-19 18:01:35 +00:00
int x ;
x = cgi_write_to_peer ( cgi , HIO_NULL , 0 ) ;
2020-11-16 16:52:49 +00:00
cgi_mark_over ( cgi , CGI_OVER_READ_FROM_CLIENT ) ;
2023-03-19 18:01:35 +00:00
if ( x < = - 1 ) goto oops ;
2020-05-25 08:04:30 +00:00
}
}
2023-03-19 18:01:35 +00:00
#if 0
2020-05-25 08:04:30 +00:00
else
{
2021-07-22 07:30:20 +00:00
hio_oow_t rem ;
2020-05-25 08:04:30 +00:00
2021-07-22 07:30:20 +00:00
HIO_ASSERT ( hio , ! ( cgi - > over & CGI_OVER_READ_FROM_CLIENT ) ) ;
2020-05-25 08:04:30 +00:00
2021-07-22 07:30:20 +00:00
if ( hio_htrd_feed ( cli - > htrd , buf , len , & rem ) < = - 1 ) goto oops ;
2020-05-25 08:04:30 +00:00
if ( rem > 0 )
{
/* TODO store this to client buffer. once the current resource is completed, arrange to call on_read() with it */
2022-06-25 16:00:28 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - excessive data after contents by cgi client %p(%d) \n " , sck - > hio , sck , ( int ) sck - > hnd ) ;
2020-05-25 08:04:30 +00:00
}
}
2023-03-19 18:01:35 +00:00
# endif
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
if ( n < = - 1 ) goto oops ;
2020-05-25 08:04:30 +00:00
return 0 ;
oops :
2020-11-16 16:52:49 +00:00
cgi_halt_participating_devices ( cgi ) ;
2020-05-25 08:04:30 +00:00
return 0 ;
}
2021-07-22 07:30:20 +00:00
static int cgi_client_on_write ( hio_dev_sck_t * sck , hio_iolen_t wrlen , void * wrctx , const hio_skad_t * dstaddr )
2020-05-25 08:04:30 +00:00
{
2021-07-22 07:30:20 +00:00
hio_t * hio = sck - > hio ;
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( sck ) ;
2023-01-11 15:41:01 +00:00
cgi_t * cgi = ( cgi_t * ) cli - > task ;
2023-03-19 18:01:35 +00:00
int n ;
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
n = cgi - > client_org_on_write ? cgi - > client_org_on_write ( sck , wrlen , wrctx , dstaddr ) : 0 ;
2020-05-25 08:04:30 +00:00
if ( wrlen = = 0 )
{
/* if the connect is keep-alive, this part may not be called */
2023-01-14 15:59:43 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - indicated EOF to client %p(%d) \n " , cgi - > htts , sck , ( int ) sck - > hnd ) ;
2020-05-25 08:04:30 +00:00
/* 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 */
2020-11-16 16:52:49 +00:00
cgi_mark_over ( cgi , CGI_OVER_WRITE_TO_CLIENT ) ;
2020-05-25 08:04:30 +00:00
}
else
{
2023-03-19 18:01:35 +00:00
if ( cgi - > peer & & cgi - > task_res_pending_writes = = CGI_PENDING_IO_THRESHOLD )
2020-05-25 08:04:30 +00:00
{
2023-03-19 18:01:35 +00:00
/* enable input watching */
2020-11-16 16:52:49 +00:00
if ( ! ( cgi - > over & CGI_OVER_READ_FROM_PEER ) & &
2023-03-19 18:01:35 +00:00
hio_dev_pro_read ( cgi - > peer , HIO_DEV_PRO_OUT , 1 ) < = - 1 ) n = - 1 ;
2020-05-25 08:04:30 +00:00
}
2023-03-19 18:01:35 +00:00
if ( ( cgi - > over & CGI_OVER_READ_FROM_PEER ) & & cgi - > task_res_pending_writes < = 0 )
2020-05-25 08:04:30 +00:00
{
2020-11-16 16:52:49 +00:00
cgi_mark_over ( cgi , CGI_OVER_WRITE_TO_CLIENT ) ;
2020-05-25 08:04:30 +00:00
}
}
2023-03-19 18:01:35 +00:00
if ( n < = - 1 | | wrlen < = - 1 ) cgi_halt_participating_devices ( cgi ) ;
2020-05-25 08:04:30 +00:00
return 0 ;
}
2023-03-19 18:01:35 +00:00
/* ----------------------------------------------------------------------- */
2022-08-31 23:01:32 +00:00
struct peer_fork_ctx_t
2020-05-25 08:04:30 +00:00
{
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_t * cli ;
hio_htre_t * req ;
const hio_bch_t * docroot ;
const hio_bch_t * script ;
hio_bch_t * actual_script ;
2020-05-25 08:04:30 +00:00
} ;
2022-08-31 23:01:32 +00:00
typedef struct peer_fork_ctx_t peer_fork_ctx_t ;
2020-05-25 08:04:30 +00:00
2022-08-31 23:01:32 +00:00
static int peer_capture_request_header ( hio_htre_t * req , const hio_bch_t * key , const hio_htre_hdrval_t * val , void * ctx )
2020-05-25 08:04:30 +00:00
{
2021-07-22 07:30:20 +00:00
hio_becs_t * dbuf = ( hio_becs_t * ) ctx ;
2020-05-25 08:04:30 +00:00
2021-07-22 07:30:20 +00:00
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 )
2020-05-25 08:04:30 +00:00
{
2021-07-22 07:30:20 +00:00
hio_oow_t val_offset ;
hio_bch_t * ptr ;
2020-05-25 08:04:30 +00:00
2021-07-22 07:30:20 +00:00
hio_becs_clear ( dbuf ) ;
if ( hio_becs_cpy ( dbuf , " HTTP_ " ) = = ( hio_oow_t ) - 1 | |
hio_becs_cat ( dbuf , key ) = = ( hio_oow_t ) - 1 | |
hio_becs_ccat ( dbuf , ' \0 ' ) = = ( hio_oow_t ) - 1 ) return - 1 ;
2020-05-25 08:04:30 +00:00
2021-07-22 07:30:20 +00:00
for ( ptr = HIO_BECS_PTR ( dbuf ) ; * ptr ; ptr + + )
2020-05-25 08:04:30 +00:00
{
2021-07-22 07:30:20 +00:00
* ptr = hio_to_bch_upper ( * ptr ) ;
2020-05-25 08:04:30 +00:00
if ( * ptr = = ' - ' ) * ptr = ' _ ' ;
}
2021-07-22 07:30:20 +00:00
val_offset = HIO_BECS_LEN ( dbuf ) ;
if ( hio_becs_cat ( dbuf , val - > ptr ) = = ( hio_oow_t ) - 1 ) return - 1 ;
2020-05-25 08:04:30 +00:00
val = val - > next ;
while ( val )
{
2021-07-22 07:30:20 +00:00
if ( hio_becs_cat ( dbuf , " , " ) = = ( hio_oow_t ) - 1 | |
hio_becs_cat ( dbuf , val - > ptr ) = = ( hio_oow_t ) - 1 ) return - 1 ;
2020-05-25 08:04:30 +00:00
val = val - > next ;
}
2021-07-22 07:30:20 +00:00
setenv ( HIO_BECS_PTR ( dbuf ) , HIO_BECS_CPTR ( dbuf , val_offset ) , 1 ) ;
2020-05-25 08:04:30 +00:00
}
return 0 ;
}
2023-01-14 14:54:54 +00:00
static int cgi_peer_on_fork ( hio_dev_pro_t * pro , void * fork_ctx )
2020-05-25 08:04:30 +00:00
{
2021-07-22 07:30:20 +00:00
hio_t * hio = pro - > hio ; /* in this callback, the pro device is not fully up. however, the hio field is guaranteed to be available */
2022-08-31 23:01:32 +00:00
peer_fork_ctx_t * fc = ( peer_fork_ctx_t * ) fork_ctx ;
2021-07-22 07:30:20 +00:00
hio_oow_t content_length ;
const hio_bch_t * qparam ;
2022-06-26 04:16:32 +00:00
const hio_bch_t * tmpstr ;
2021-07-22 07:30:20 +00:00
hio_bch_t * path , * lang ;
hio_bch_t tmp [ 256 ] ;
hio_becs_t dbuf ;
2020-05-25 08:04:30 +00:00
2021-07-22 07:30:20 +00:00
qparam = hio_htre_getqparam ( fc - > req ) ;
2023-01-14 17:17:12 +00:00
/* the anchor/fragment is never part of the server-side URL.
* the client must discard that part before sending to the server .
* hio_htre_getqanchor ( ) is just disregarded here . */
2020-05-25 08:04:30 +00:00
2022-06-26 04:16:32 +00:00
tmpstr = getenv ( " PATH " ) ;
if ( ! tmpstr ) tmpstr = " " ;
path = hio_dupbcstr ( hio , tmpstr , HIO_NULL ) ;
tmpstr = getenv ( " LANG " ) ;
if ( ! tmpstr ) tmpstr = " " ;
lang = hio_dupbcstr ( hio , tmpstr , HIO_NULL ) ;
2020-05-25 08:04:30 +00:00
# if defined(HAVE_CLEARENV)
clearenv ( ) ;
2022-06-22 13:14:35 +00:00
# elif defined(HAVE_CRT_EXTERNS_H)
{
char * * environ = * _NSGetEnviron ( ) ;
if ( environ ) environ [ 0 ] = ' \0 ' ;
}
2020-05-25 08:04:30 +00:00
# else
{
extern char * * environ ;
/* environ = NULL; this crashed this program on NetBSD */
if ( environ ) environ [ 0 ] = ' \0 ' ;
}
# endif
2023-01-11 14:59:41 +00:00
if ( path )
2020-05-25 08:04:30 +00:00
{
setenv ( " PATH " , path , 1 ) ;
2021-07-22 07:30:20 +00:00
hio_freemem ( hio , path ) ;
2020-05-25 08:04:30 +00:00
}
2023-01-11 14:59:41 +00:00
if ( lang )
2020-05-25 08:04:30 +00:00
{
setenv ( " LANG " , lang , 1 ) ;
2021-07-22 07:30:20 +00:00
hio_freemem ( hio , lang ) ;
2020-05-25 08:04:30 +00:00
}
setenv ( " GATEWAY_INTERFACE " , " CGI/1.1 " , 1 ) ;
2021-07-22 07:30:20 +00:00
hio_fmttobcstr ( hio , tmp , HIO_COUNTOF ( tmp ) , " HTTP/%d.%d " , ( int ) hio_htre_getmajorversion ( fc - > req ) , ( int ) hio_htre_getminorversion ( fc - > req ) ) ;
2020-05-25 08:04:30 +00:00
setenv ( " SERVER_PROTOCOL " , tmp , 1 ) ;
setenv ( " DOCUMENT_ROOT " , fc - > docroot , 1 ) ;
setenv ( " SCRIPT_NAME " , fc - > script , 1 ) ;
setenv ( " SCRIPT_FILENAME " , fc - > actual_script , 1 ) ;
/* TODO: PATH_INFO */
2021-07-22 07:30:20 +00:00
setenv ( " REQUEST_METHOD " , hio_htre_getqmethodname ( fc - > req ) , 1 ) ;
setenv ( " REQUEST_URI " , hio_htre_getqpath ( fc - > req ) , 1 ) ;
2023-01-14 17:17:12 +00:00
2020-05-25 08:04:30 +00:00
if ( qparam ) setenv ( " QUERY_STRING " , qparam , 1 ) ;
2021-07-22 07:30:20 +00:00
if ( hio_htre_getreqcontentlen ( fc - > req , & content_length ) = = 0 )
2020-05-25 08:04:30 +00:00
{
2021-07-22 07:30:20 +00:00
hio_fmt_uintmax_to_bcstr ( tmp , HIO_COUNTOF ( tmp ) , content_length , 10 , 0 , ' \0 ' , HIO_NULL ) ;
2020-05-25 08:04:30 +00:00
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 ) ;
2021-07-22 07:30:20 +00:00
hio_skadtobcstr ( hio , & fc - > cli - > sck - > localaddr , tmp , HIO_COUNTOF ( tmp ) , HIO_SKAD_TO_BCSTR_ADDR ) ;
2020-05-25 08:04:30 +00:00
setenv ( " SERVER_ADDR " , tmp , 1 ) ;
2021-07-22 07:30:20 +00:00
gethostname ( tmp , HIO_COUNTOF ( tmp ) ) ; /* if this fails, i assume tmp contains the ip address set by hio_skadtobcstr() above */
2020-05-25 08:04:30 +00:00
setenv ( " SERVER_NAME " , tmp , 1 ) ;
2021-07-22 07:30:20 +00:00
hio_skadtobcstr ( hio , & fc - > cli - > sck - > localaddr , tmp , HIO_COUNTOF ( tmp ) , HIO_SKAD_TO_BCSTR_PORT ) ;
2020-05-25 08:04:30 +00:00
setenv ( " SERVER_PORT " , tmp , 1 ) ;
2021-07-22 07:30:20 +00:00
hio_skadtobcstr ( hio , & fc - > cli - > sck - > remoteaddr , tmp , HIO_COUNTOF ( tmp ) , HIO_SKAD_TO_BCSTR_ADDR ) ;
2020-05-25 08:04:30 +00:00
setenv ( " REMOTE_ADDR " , tmp , 1 ) ;
2021-07-22 07:30:20 +00:00
hio_skadtobcstr ( hio , & fc - > cli - > sck - > remoteaddr , tmp , HIO_COUNTOF ( tmp ) , HIO_SKAD_TO_BCSTR_PORT ) ;
2020-05-25 08:04:30 +00:00
setenv ( " REMOTE_PORT " , tmp , 1 ) ;
2021-07-22 07:30:20 +00:00
if ( hio_becs_init ( & dbuf , hio , 256 ) > = 0 )
2020-05-25 08:04:30 +00:00
{
2022-08-31 23:01:32 +00:00
hio_htre_walkheaders ( fc - > req , peer_capture_request_header , & dbuf ) ;
2021-07-22 07:30:20 +00:00
/* [NOTE] trailers are not available when this cgi resource is started. let's not call hio_htre_walktrailers() */
hio_becs_fini ( & dbuf ) ;
2020-05-25 08:04:30 +00:00
}
return 0 ;
}
2023-03-19 18:01:35 +00:00
static void bind_task_to_client ( cgi_t * cgi , hio_dev_sck_t * csck )
2020-05-25 08:04:30 +00:00
{
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( csck ) ;
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
HIO_ASSERT ( cgi - > htts - > hio , cli - > sck = = csck ) ;
HIO_ASSERT ( cgi - > htts - > hio , cli - > task = = HIO_NULL ) ;
/* cgi->task_client and cgi->task_csck are set in hio_svc_htts_task_make() */
/* remember the client socket's io event handlers */
cgi - > client_org_on_read = csck - > on_read ;
cgi - > client_org_on_write = csck - > on_write ;
cgi - > client_org_on_disconnect = csck - > on_disconnect ;
/* set new io events handlers on the client socket */
csck - > on_read = cgi_client_on_read ;
csck - > on_write = cgi_client_on_write ;
csck - > on_disconnect = cgi_client_on_disconnect ;
cli - > task = ( hio_svc_htts_task_t * ) cgi ;
HIO_SVC_HTTS_TASK_RCUP ( cgi ) ;
}
static void unbind_task_from_client ( cgi_t * cgi , int rcdown )
{
hio_dev_sck_t * csck = cgi - > task_csck ;
HIO_ASSERT ( cgi - > htts - > hio , cgi - > task_client ! = HIO_NULL ) ;
HIO_ASSERT ( cgi - > htts - > hio , cgi - > task_csck ! = HIO_NULL ) ;
HIO_ASSERT ( cgi - > htts - > hio , cgi - > task_client - > task = = ( hio_svc_htts_task_t * ) cgi ) ;
HIO_ASSERT ( cgi - > htts - > hio , cgi - > task_client - > htrd ! = HIO_NULL ) ;
if ( cgi - > client_htrd_recbs_changed )
{
hio_htrd_setrecbs ( cgi - > task_client - > htrd , & cgi - > client_htrd_org_recbs ) ;
cgi - > client_htrd_recbs_changed = 0 ;
}
if ( cgi - > client_org_on_read )
{
csck - > on_read = cgi - > client_org_on_read ;
cgi - > client_org_on_read = HIO_NULL ;
}
if ( cgi - > client_org_on_write )
{
csck - > on_write = cgi - > client_org_on_write ;
cgi - > client_org_on_write = HIO_NULL ;
}
if ( cgi - > client_org_on_disconnect )
{
csck - > on_disconnect = cgi - > client_org_on_disconnect ;
cgi - > client_org_on_disconnect = HIO_NULL ;
}
/* there is some ordering issue in using HIO_SVC_HTTS_TASK_UNREF()
* because it can destroy the cgi itself . so reset cgi - > task_client - > task
* to null and call RCDOWN ( ) later */
cgi - > task_client - > task = HIO_NULL ;
/* these two lines are also done in csck_on_disconnect() in http-svr.c because the socket is destroyed.
* the same lines here are because the task is unbound while the socket is still alive */
cgi - > task_client = HIO_NULL ;
cgi - > task_csck = HIO_NULL ;
/* enable input watching on the socket being unbound */
if ( cgi - > task_keep_client_alive & & hio_dev_sck_read ( csck , 1 ) < = - 1 )
{
HIO_DEBUG2 ( cgi - > htts - > hio , " HTTS(%p) - halting client(%p) for failure to enable input watching \n " , cgi - > htts , csck ) ;
hio_dev_sck_halt ( csck ) ;
}
if ( rcdown ) HIO_SVC_HTTS_TASK_RCDOWN ( ( hio_svc_htts_task_t * ) cgi ) ;
}
/* ----------------------------------------------------------------------- */
static int bind_task_to_peer ( cgi_t * cgi , hio_dev_sck_t * csck , hio_htre_t * req , const hio_bch_t * docroot , const hio_bch_t * script )
{
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( csck ) ;
hio_svc_htts_t * htts = cgi - > htts ;
hio_t * hio = htts - > hio ;
peer_fork_ctx_t fc ;
hio_dev_pro_make_t mi ;
cgi_peer_xtn_t * peer_xtn ;
2023-02-06 13:30:56 +00:00
2021-07-22 07:30:20 +00:00
HIO_MEMSET ( & fc , 0 , HIO_SIZEOF ( fc ) ) ;
2020-05-25 08:04:30 +00:00
fc . cli = cli ;
fc . req = req ;
fc . docroot = docroot ;
fc . script = script ;
2021-07-22 07:30:20 +00:00
fc . actual_script = hio_svc_htts_dupmergepaths ( htts , docroot , script ) ;
2023-03-19 18:01:35 +00:00
if ( ! fc . actual_script ) return - 1 ;
2020-05-25 08:04:30 +00:00
2021-07-22 07:30:20 +00:00
HIO_MEMSET ( & mi , 0 , HIO_SIZEOF ( mi ) ) ;
mi . flags = HIO_DEV_PRO_READOUT | HIO_DEV_PRO_ERRTONUL | HIO_DEV_PRO_WRITEIN /*| HIO_DEV_PRO_FORGET_CHILD*/ ;
2020-05-25 08:04:30 +00:00
mi . cmd = fc . actual_script ;
2023-01-14 14:54:54 +00:00
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 ;
2020-05-25 08:04:30 +00:00
mi . fork_ctx = & fc ;
if ( access ( mi . cmd , X_OK ) = = - 1 )
{
2023-03-19 18:01:35 +00:00
/* not executable */
hio_freemem ( hio , fc . actual_script ) ;
return - 2 ;
2020-05-25 08:04:30 +00:00
}
2022-09-05 23:19:08 +00:00
cgi - > peer = hio_dev_pro_make ( hio , HIO_SIZEOF ( * peer_xtn ) , & mi ) ;
2023-03-19 18:01:35 +00:00
if ( HIO_UNLIKELY ( ! cgi - > peer ) )
{
hio_freemem ( hio , fc . actual_script ) ;
return - 1 ;
}
hio_freemem ( hio , fc . actual_script ) ;
2020-05-25 08:04:30 +00:00
2022-09-05 23:19:08 +00:00
cgi - > peer_htrd = hio_htrd_open ( hio , HIO_SIZEOF ( * peer_xtn ) ) ;
2023-03-19 18:01:35 +00:00
if ( HIO_UNLIKELY ( ! cgi - > peer_htrd ) )
{
hio_freemem ( hio , fc . actual_script ) ;
hio_dev_pro_kill ( cgi - > peer ) ;
return - 1 ;
}
2021-07-22 07:30:20 +00:00
hio_htrd_setoption ( cgi - > peer_htrd , HIO_HTRD_SKIP_INITIAL_LINE | HIO_HTRD_RESPONSE ) ;
2022-08-31 23:01:32 +00:00
hio_htrd_setrecbs ( cgi - > peer_htrd , & peer_htrd_recbs ) ;
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
peer_xtn = hio_dev_pro_getxtn ( cgi - > peer ) ;
peer_xtn - > cgi = cgi ;
HIO_SVC_HTTS_TASK_RCUP ( cgi ) ;
2022-09-05 23:19:08 +00:00
peer_xtn = hio_htrd_getxtn ( cgi - > peer_htrd ) ;
2023-03-19 18:01:35 +00:00
peer_xtn - > cgi = cgi ;
HIO_SVC_HTTS_TASK_RCUP ( cgi ) ;
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
return 0 ;
}
2023-01-11 14:59:41 +00:00
2023-03-19 18:01:35 +00:00
static void unbind_task_from_peer ( cgi_t * cgi , int rcdown )
{
int n = 0 ;
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
if ( cgi - > peer_htrd )
{
hio_htrd_close ( cgi - > peer_htrd ) ;
cgi - > peer_htrd = HIO_NULL ;
n + + ;
2020-05-25 08:04:30 +00:00
}
2023-03-19 18:01:35 +00:00
if ( cgi - > peer )
2020-05-25 08:04:30 +00:00
{
2023-03-19 18:01:35 +00:00
hio_dev_pro_kill ( cgi - > peer ) ;
cgi - > peer = HIO_NULL ;
n + + ;
2020-05-25 08:04:30 +00:00
}
2023-03-19 18:01:35 +00:00
if ( rcdown )
2020-05-25 08:04:30 +00:00
{
2023-03-19 18:01:35 +00:00
while ( n > 0 )
{
n - - ;
HIO_SVC_HTTS_TASK_RCDOWN ( ( hio_svc_htts_task_t * ) cgi ) ;
}
2020-05-25 08:04:30 +00:00
}
2023-03-19 18:01:35 +00:00
}
/* ----------------------------------------------------------------------- */
2020-05-25 08:04:30 +00:00
2023-03-19 18:01:35 +00:00
static int setup_for_content_length ( cgi_t * cgi , hio_htre_t * req )
{
2020-05-25 08:04:30 +00:00
# if defined(CGI_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH)
2023-03-18 20:04:32 +00:00
if ( cgi - > task_req_conlen_unlimited )
2020-05-25 08:04:30 +00:00
{
/* change the callbacks to subscribe to contents to be uploaded */
2023-03-04 15:55:15 +00:00
cgi - > client_htrd_org_recbs = * hio_htrd_getrecbs ( cgi - > task_client - > htrd ) ;
2020-11-16 16:52:49 +00:00
cgi_client_htrd_recbs . peek = cgi - > client_htrd_org_recbs . peek ;
2023-03-04 15:55:15 +00:00
hio_htrd_setrecbs ( cgi - > task_client - > htrd , & cgi_client_htrd_recbs ) ;
2020-11-16 16:52:49 +00:00
cgi - > client_htrd_recbs_changed = 1 ;
2020-05-25 08:04:30 +00:00
}
else
{
# endif
2023-03-18 20:04:32 +00:00
if ( cgi - > task_req_conlen > 0 )
2020-05-25 08:04:30 +00:00
{
/* change the callbacks to subscribe to contents to be uploaded */
2023-03-04 15:55:15 +00:00
cgi - > client_htrd_org_recbs = * hio_htrd_getrecbs ( cgi - > task_client - > htrd ) ;
2020-11-16 16:52:49 +00:00
cgi_client_htrd_recbs . peek = cgi - > client_htrd_org_recbs . peek ;
2023-03-04 15:55:15 +00:00
hio_htrd_setrecbs ( cgi - > task_client - > htrd , & cgi_client_htrd_recbs ) ;
2020-11-16 16:52:49 +00:00
cgi - > client_htrd_recbs_changed = 1 ;
2020-05-25 08:04:30 +00:00
}
else
{
/* no content to be uploaded from the client */
/* indicate EOF to the peer and disable input wathching from the client */
2023-03-19 18:01:35 +00:00
if ( cgi_write_to_peer ( cgi , HIO_NULL , 0 ) < = - 1 ) return - 1 ;
2020-11-16 16:52:49 +00:00
cgi_mark_over ( cgi , CGI_OVER_READ_FROM_CLIENT | CGI_OVER_WRITE_TO_PEER ) ;
2020-05-25 08:04:30 +00:00
}
# if defined(CGI_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH)
}
# endif
2023-03-19 18:01:35 +00:00
return 0 ;
}
/* ----------------------------------------------------------------------- */
int hio_svc_htts_docgi ( hio_svc_htts_t * htts , hio_dev_sck_t * csck , hio_htre_t * req , const hio_bch_t * docroot , const hio_bch_t * script , int options , hio_svc_htts_task_on_kill_t on_kill )
{
hio_t * hio = htts - > hio ;
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( csck ) ;
cgi_t * cgi = HIO_NULL ;
int n ;
/* ensure that you call this function before any contents is received */
HIO_ASSERT ( hio , hio_htre_getcontentlen ( req ) = = 0 ) ;
HIO_ASSERT ( hio , cli - > sck = = csck ) ;
cgi = ( cgi_t * ) hio_svc_htts_task_make ( htts , HIO_SIZEOF ( * cgi ) , cgi_on_kill , req , csck ) ;
if ( HIO_UNLIKELY ( ! cgi ) ) goto oops ;
cgi - > on_kill = on_kill ;
cgi - > options = options ;
bind_task_to_client ( cgi , csck ) ;
if ( ( n = bind_task_to_peer ( cgi , csck , req , docroot , script ) ) < = - 1 )
{
hio_svc_htts_task_sendfinalres ( cgi , ( n = = 2 ? HIO_HTTP_STATUS_FORBIDDEN : HIO_HTTP_STATUS_INTERNAL_SERVER_ERROR ) , HIO_NULL , HIO_NULL , 1 ) ;
goto oops ; /* TODO: must not go to oops. just destroy the cgi and finalize the request .. */
}
if ( hio_svc_htts_task_handleexpect100 ( cgi , options ) < = - 1 ) goto oops ;
if ( setup_for_content_length ( cgi , req ) < = - 1 ) goto oops ;
2020-05-25 08:04:30 +00:00
2020-11-16 16:52:49 +00:00
/* TODO: store current input watching state and use it when destroying the cgi data */
2021-07-22 07:30:20 +00:00
if ( hio_dev_sck_read ( csck , ! ( cgi - > over & CGI_OVER_READ_FROM_CLIENT ) ) < = - 1 ) goto oops ;
2023-01-14 14:54:54 +00:00
2023-01-27 15:41:44 +00:00
HIO_SVC_HTTS_TASKL_APPEND_TASK ( & htts - > task , ( hio_svc_htts_task_t * ) cgi ) ;
2020-05-25 08:04:30 +00:00
return 0 ;
oops :
2021-07-22 07:30:20 +00:00
HIO_DEBUG2 ( hio , " HTTS(%p) - FAILURE in docgi - socket(%p) \n " , htts , csck ) ;
2020-11-16 16:52:49 +00:00
if ( cgi ) cgi_halt_participating_devices ( cgi ) ;
2020-05-25 08:04:30 +00:00
return - 1 ;
}