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-path.h>
2023-03-11 03:54:36 +00:00
# include <hio-fmt.h>
2021-08-10 10:32:36 +00:00
# include <errno.h>
2023-03-10 17:32:33 +00:00
# include <stdarg.h>
2020-05-05 15:12:08 +00:00
2021-08-09 08:24:21 +00:00
# define INVALID_LIDX HIO_TYPE_MAX(hio_oow_t)
2023-03-18 20:04:32 +00:00
static int htts_svr_wrctx ;
/* ------------------------------------------------------------------------ */
static int client_on_read ( hio_dev_sck_t * sck , const void * buf , hio_iolen_t len , const hio_skad_t * srcaddr ) ;
static int client_on_write ( hio_dev_sck_t * sck , hio_iolen_t wrlen , void * wrctx , const hio_skad_t * dstaddr ) ;
static void client_on_disconnect ( hio_dev_sck_t * sck ) ;
2020-05-05 15:12:08 +00:00
/* ------------------------------------------------------------------------ */
2021-07-22 07:30:20 +00:00
static int client_htrd_peek_request ( hio_htrd_t * htrd , hio_htre_t * req )
2020-05-06 09:28:36 +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_svc_htts_cli_t * sckxtn = ( hio_svc_htts_cli_t * ) hio_dev_sck_getxtn ( htrdxtn - > sck ) ;
2020-05-20 16:14:36 +00:00
return sckxtn - > htts - > proc_req ( sckxtn - > htts , htrdxtn - > sck , req ) ;
2020-05-06 09:28:36 +00:00
}
2021-07-22 07:30:20 +00:00
static hio_htrd_recbs_t client_htrd_recbs =
2020-05-06 09:28:36 +00:00
{
client_htrd_peek_request ,
2021-07-22 07:30:20 +00:00
HIO_NULL ,
HIO_NULL
2020-05-06 09:28:36 +00:00
} ;
2021-07-22 07:30:20 +00:00
static int init_client ( hio_svc_htts_cli_t * cli , hio_dev_sck_t * sck )
2020-05-06 09:28:36 +00:00
{
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_htrd_xtn_t * htrdxtn ;
2020-05-06 09:28:36 +00:00
2020-05-12 11:46:00 +00:00
/* the htts field must be filled with the same field in the listening socket upon accept() */
2021-07-22 07:30:20 +00:00
HIO_ASSERT ( sck - > hio , cli - > htts ! = HIO_NULL ) ;
2021-08-09 08:24:21 +00:00
HIO_ASSERT ( sck - > hio , cli - > l_idx < cli - > htts - > l . count ) ; /* at this point, it's still the listener's index as it's cloned */
2021-07-22 07:30:20 +00:00
HIO_ASSERT ( sck - > hio , sck - > hio = = cli - > htts - > hio ) ;
2020-05-06 09:28:36 +00:00
2020-07-16 10:46:17 +00:00
cli - > sck = sck ;
2022-10-08 07:47:55 +00:00
if ( hio_dev_sck_getpeeraddr ( sck , & cli - > cli_addr ) > = 0 )
hio_skadtobcstr ( sck - > hio , & cli - > cli_addr , cli - > cli_addr_bcstr , HIO_COUNTOF ( cli - > cli_addr_bcstr ) , HIO_SKAD_TO_BCSTR_ADDR | HIO_SKAD_TO_BCSTR_PORT ) ;
2021-08-09 08:24:21 +00:00
cli - > l_idx = INVALID_LIDX ; /* not a listening socket anymore */
2021-07-22 07:30:20 +00:00
cli - > htrd = HIO_NULL ;
cli - > sbuf = HIO_NULL ;
2023-01-11 15:41:01 +00:00
cli - > task = HIO_NULL ;
2023-01-11 14:59:41 +00:00
/* keep this linked regardless of success or failure because the disconnect() callback
2020-07-16 10:46:17 +00:00
* will call fini_client ( ) . the error handler code after ' oops : ' doesn ' t get this unlinked */
2021-07-22 07:30:20 +00:00
HIO_SVC_HTTS_CLIL_APPEND_CLI ( & cli - > htts - > cli , cli ) ;
2020-07-16 10:46:17 +00:00
2021-07-22 07:30:20 +00:00
cli - > htrd = hio_htrd_open ( sck - > hio , HIO_SIZEOF ( * htrdxtn ) ) ;
if ( HIO_UNLIKELY ( ! cli - > htrd ) ) goto oops ;
2020-05-06 09:28:36 +00:00
2021-07-22 07:30:20 +00:00
/* With HIO_HTRD_TRAILERS, htrd stores trailers in a separate place.
2020-05-19 09:11:39 +00:00
* Otherwise , it is merged to the headers . */
2021-07-22 07:30:20 +00:00
/*hio_htrd_setoption (cli->htrd, HIO_HTRD_REQUEST | HIO_HTRD_TRAILERS);*/
2020-05-19 09:11:39 +00:00
2021-07-22 07:30:20 +00:00
cli - > sbuf = hio_becs_open ( sck - > hio , 0 , 2048 ) ;
if ( HIO_UNLIKELY ( ! cli - > sbuf ) ) goto oops ;
2020-05-16 19:12:10 +00:00
2021-07-22 07:30:20 +00:00
htrdxtn = hio_htrd_getxtn ( cli - > htrd ) ;
2020-05-12 11:46:00 +00:00
htrdxtn - > sck = sck ; /* TODO: remember cli instead? */
2020-05-06 09:28:36 +00:00
2021-07-22 07:30:20 +00:00
hio_htrd_setrecbs ( cli - > htrd , & client_htrd_recbs ) ;
2020-05-12 11:46:00 +00:00
2021-07-22 07:30:20 +00:00
hio_gettime ( sck - > hio , & cli - > last_active ) ;
2023-03-18 20:04:32 +00:00
HIO_DEBUG4 ( sck - > hio , " HTTS(%p) - client(c=%p,csck=%d[%d]) - initialized \n " , cli - > htts , cli , sck , ( int ) sck - > hnd ) ;
sck - > on_read = client_on_read ;
sck - > on_write = client_on_write ;
sck - > on_disconnect = client_on_disconnect ;
2020-05-06 09:28:36 +00:00
return 0 ;
oops :
2020-07-16 10:46:17 +00:00
/* since this function is called in the on_connect() callback,
* fini_client ( ) is eventually called by on_disconnect ( ) . i don ' t do clean - up here .
2023-01-11 14:59:41 +00:00
if ( cli - > sbuf )
2020-05-06 09:28:36 +00:00
{
2021-07-22 07:30:20 +00:00
hio_becs_close ( cli - > sbuf ) ;
cli - > sbuf = HIO_NULL ;
2020-05-06 09:28:36 +00:00
}
2020-05-12 11:46:00 +00:00
if ( cli - > htrd )
2020-05-06 09:28:36 +00:00
{
2021-07-22 07:30:20 +00:00
hio_htrd_close ( cli - > htrd ) ;
cli - > htrd = HIO_NULL ;
2020-07-16 10:46:17 +00:00
} */
2020-05-06 09:28:36 +00:00
return - 1 ;
}
2021-07-22 07:30:20 +00:00
static void fini_client ( hio_svc_htts_cli_t * cli )
2020-05-06 09:28:36 +00:00
{
2023-03-18 20:04:32 +00:00
HIO_DEBUG4 ( cli - > sck - > hio , " HTTS(%p) - client(c=%p,sck=%p[%d]) - finalizing \n " , cli - > htts , cli , cli - > sck , ( int ) cli - > sck - > hnd ) ;
2020-05-12 17:53:19 +00:00
2023-01-11 15:41:01 +00:00
if ( cli - > task )
2020-05-18 16:40:00 +00:00
{
2023-03-18 20:04:32 +00:00
cli - > task - > task_keep_client_alive = 0 ;
/* the client socket is not valid any longer. let's forget it */
cli - > task - > task_client = HIO_NULL ;
cli - > task - > task_csck = HIO_NULL ;
2023-01-11 15:41:01 +00:00
HIO_SVC_HTTS_TASK_UNREF ( cli - > task ) ;
2020-05-18 16:40:00 +00:00
}
2020-05-12 11:46:00 +00:00
2023-01-11 14:59:41 +00:00
if ( cli - > sbuf )
2020-05-06 09:28:36 +00:00
{
2021-07-22 07:30:20 +00:00
hio_becs_close ( cli - > sbuf ) ;
cli - > sbuf = HIO_NULL ;
2020-05-06 09:28:36 +00:00
}
2020-05-18 16:40:00 +00:00
2020-05-12 11:46:00 +00:00
if ( cli - > htrd )
2020-05-06 09:28:36 +00:00
{
2021-07-22 07:30:20 +00:00
hio_htrd_close ( cli - > htrd ) ;
cli - > htrd = HIO_NULL ;
2020-05-06 09:28:36 +00:00
}
2020-05-12 11:46:00 +00:00
2021-07-22 07:30:20 +00:00
HIO_SVC_HTTS_CLIL_UNLINK_CLI_CLEAN ( cli ) ;
2020-05-12 17:53:19 +00:00
2023-01-11 14:59:41 +00:00
/* are these needed? not symmetrical if done here.
2020-05-12 17:53:19 +00:00
* these fields are copied from the listener socket upon accept .
* init_client ( ) doesn ' t fill in these fields . let ' s comment out these lines
2021-07-22 07:30:20 +00:00
cli - > sck = HIO_NULL ;
2023-01-11 14:59:41 +00:00
cli - > htts = HIO_NULL ;
2020-05-12 17:53:19 +00:00
*/
2023-03-18 20:04:32 +00:00
HIO_DEBUG4 ( cli - > sck - > hio , " HTTS(%p) - client(c=%p,sck=%p[%d]) - finalized \n " , cli - > htts , cli , cli - > sck , ( int ) cli - > sck - > hnd ) ;
2020-05-06 09:28:36 +00:00
}
/* ------------------------------------------------------------------------ */
2021-07-22 07:30:20 +00:00
static int listener_on_read ( hio_dev_sck_t * sck , const void * buf , hio_iolen_t len , const hio_skad_t * srcaddr )
2020-05-05 15:12:08 +00:00
{
2023-03-18 20:04:32 +00:00
/* unlike the function name, this callback is set on both the listener and the client initially.
* init_client ( ) changes the socket ' s on_read to client_on_read . so this hander must never be called */
if ( len < = - 1 ) hio_dev_sck_halt ( sck ) ;
2020-05-05 15:12:08 +00:00
return 0 ;
}
2021-07-22 07:30:20 +00:00
static int listener_on_write ( hio_dev_sck_t * sck , hio_iolen_t wrlen , void * wrctx , const hio_skad_t * dstaddr )
2020-05-05 15:12:08 +00:00
{
2021-08-09 08:24:21 +00:00
/* don't get deluded by the name. it's set on both the listener and the client.
* it is not supposed to be triggered on the listener , however */
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( sck ) ;
2021-08-09 08:24:21 +00:00
HIO_ASSERT ( sck - > hio , cli - > l_idx = = INVALID_LIDX ) ;
2023-03-18 20:04:32 +00:00
#if 0
2023-01-11 15:41:01 +00:00
/* if a resource has been set(cli->task not NULL), the resource must take over
2021-08-09 08:24:21 +00:00
* this handler . this handler is never called unless the the overriding handler
* call this . */
2023-01-11 15:41:01 +00:00
HIO_ASSERT ( sck - > hio , cli - > task = = HIO_NULL ) ;
2023-03-18 20:04:32 +00:00
# endif
2021-08-09 08:24:21 +00:00
/* anyways, nothing to do upon write completion */
2020-05-10 16:20:39 +00:00
return 0 ;
2020-05-05 15:12:08 +00:00
}
2021-07-22 07:30:20 +00:00
static void listener_on_connect ( hio_dev_sck_t * sck )
2020-05-05 15:12:08 +00:00
{
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( sck ) ; /* the contents came from the listening socket */
2020-05-05 15:12:08 +00:00
2021-07-22 07:30:20 +00:00
if ( sck - > state & HIO_DEV_SCK_ACCEPTED )
2020-05-05 15:12:08 +00:00
{
/* accepted a new client */
2022-10-08 07:47:55 +00:00
HIO_DEBUG3 ( sck - > hio , " HTTS(%p) - accepted client(%p,%d) \n " , cli - > htts , sck , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
2020-05-12 11:46:00 +00:00
if ( init_client ( cli , sck ) < = - 1 )
2020-05-05 15:12:08 +00:00
{
2022-10-08 07:47:55 +00:00
HIO_DEBUG3 ( cli - > htts - > hio , " HTTS(%p) - halting client(%p,%d) for client intiaialization failure \n " , cli - > htts , sck , ( int ) sck - > hnd ) ;
2021-07-22 07:30:20 +00:00
hio_dev_sck_halt ( sck ) ;
2020-05-05 15:12:08 +00:00
}
}
2021-07-22 07:30:20 +00:00
else if ( sck - > state & HIO_DEV_SCK_CONNECTED )
2020-05-05 15:12:08 +00:00
{
2021-07-22 07:30:20 +00:00
/* this will never be triggered as the listing socket never call hio_dev_sck_connect() */
2022-10-08 07:47:55 +00:00
HIO_DEBUG3 ( sck - > hio , " HTTS(%p) - connected (%p,%d) \n " , cli - > htts , sck , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
}
2021-07-22 07:30:20 +00:00
/* HIO_DEV_SCK_CONNECTED must not be seen here as this is only for the listener socket */
2020-05-05 15:12:08 +00:00
}
2021-07-22 07:30:20 +00:00
static void listener_on_disconnect ( hio_dev_sck_t * sck )
2020-05-05 15:12:08 +00:00
{
2021-07-22 07:30:20 +00:00
hio_t * hio = sck - > hio ;
2021-08-06 03:23:48 +00:00
hio_svc_htts_cli_t * xtn = hio_dev_sck_getxtn ( sck ) ;
2023-01-11 14:59:41 +00:00
hio_svc_htts_t * htts = xtn - > htts ;
2020-05-05 15:12:08 +00:00
2021-07-22 07:30:20 +00:00
switch ( HIO_DEV_SCK_GET_PROGRESS ( sck ) )
2020-05-05 15:12:08 +00:00
{
2021-07-22 07:30:20 +00:00
case HIO_DEV_SCK_CONNECTING :
2020-05-07 10:10:33 +00:00
/* only for connecting sockets */
2023-01-11 14:59:41 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - OUTGOING SESSION DISCONNECTED - FAILED TO CONNECT %p[%d] TO REMOTE SERVER \n " , htts , sck , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
break ;
2021-07-22 07:30:20 +00:00
case HIO_DEV_SCK_CONNECTING_SSL :
2020-05-07 10:10:33 +00:00
/* only for connecting sockets */
2023-01-11 14:59:41 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - OUTGOING SESSION DISCONNECTED - FAILED TO SSL-CONNECT %p[%d] TO REMOTE SERVER \n " , htts , sck , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
break ;
2021-07-22 07:30:20 +00:00
case HIO_DEV_SCK_CONNECTED :
2020-05-07 10:10:33 +00:00
/* only for connecting sockets */
2023-01-11 14:59:41 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - OUTGOING CLIENT CONNECTION GOT TORN DOWN %p[%d]....... \n " , htts , sck , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
break ;
2021-07-22 07:30:20 +00:00
case HIO_DEV_SCK_LISTENING :
2023-01-11 14:59:41 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - LISTNER SOCKET %p[%d] - SHUTTUING DOWN \n " , htts , sck , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
break ;
2021-07-22 07:30:20 +00:00
case HIO_DEV_SCK_ACCEPTING_SSL : /* special case. */
2020-05-12 17:53:19 +00:00
/* this progress code indicates that the ssl-level accept failed.
2023-01-11 14:59:41 +00:00
* on_disconnected ( ) with this code is called without corresponding on_connect ( ) .
2020-05-12 17:53:19 +00:00
* the cli extension are is not initialized yet */
2021-08-06 03:23:48 +00:00
HIO_ASSERT ( hio , sck ! = xtn - > sck ) ;
2023-03-18 20:04:32 +00:00
/*HIO_ASSERT (hio, 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 */
2023-01-11 14:59:41 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - LISTENER UNABLE TO SSL-ACCEPT CLIENT %p[%d] \n " , htts , sck , ( int ) sck - > hnd ) ;
2020-05-12 17:53:19 +00:00
return ;
2020-05-05 15:12:08 +00:00
2021-07-22 07:30:20 +00:00
case HIO_DEV_SCK_ACCEPTED :
2020-05-07 10:10:33 +00:00
/* 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 ( ) */
2023-01-11 14:59:41 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - ACCEPTED CLIENT SOCKET %p[%d] GOT DISCONNECTED \n " , htts , sck , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
break ;
default :
2023-01-11 14:59:41 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - SOCKET %p[%d] DISCONNECTED AFTER ALL \n " , htts , sck , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
break ;
}
2021-08-06 03:23:48 +00:00
if ( xtn - > l_idx < xtn - > htts - > l . count )
2020-05-12 17:53:19 +00:00
{
/* the listener socket has these fields set to NULL */
2021-08-06 03:23:48 +00:00
HIO_ASSERT ( hio , xtn - > htrd = = HIO_NULL ) ;
HIO_ASSERT ( hio , xtn - > sbuf = = HIO_NULL ) ;
2020-05-07 04:32:32 +00:00
2023-01-11 14:59:41 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - listener socket disconnect %p[%d] \n " , xtn - > htts , sck , ( int ) sck - > hnd ) ;
2021-08-06 03:23:48 +00:00
xtn - > htts - > l . sck [ xtn - > l_idx ] = HIO_NULL ; /* let the htts service forget about this listening socket */
2020-05-12 17:53:19 +00:00
}
else
{
/* client socket */
2023-03-18 20:04:32 +00:00
client_on_disconnect ( sck ) ;
2020-05-12 17:53:19 +00:00
}
2020-05-05 15:12:08 +00:00
}
2023-03-18 20:04:32 +00:00
/* --------------------------------------------------------------- */
static int client_on_read ( hio_dev_sck_t * sck , const void * buf , hio_iolen_t len , const hio_skad_t * srcaddr )
{
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( sck ) ;
hio_t * hio = sck - > hio ;
hio_svc_htts_t * htts = cli - > htts ;
hio_svc_htts_task_t * task = cli - > task ;
hio_oow_t rem ;
int x ;
HIO_ASSERT ( hio , cli - > l_idx = = INVALID_LIDX ) ;
if ( len < = - 1 )
{
HIO_DEBUG3 ( hio , " HTTS(%p) - unable to read client %p(%d) \n " , htts , sck , ( int ) sck - > hnd ) ;
if ( task ) task - > task_keep_client_alive = 0 ;
goto oops ;
}
if ( len = = 0 )
{
HIO_DEBUG3 ( hio , " HTTS(%p) - EOF on client %p(%d) \n " , htts , sck , ( int ) sck - > hnd ) ;
if ( task ) task - > task_keep_client_alive = 0 ;
goto oops ;
}
hio_gettime ( hio , & cli - > last_active ) ;
if ( ( x = hio_htrd_feed ( cli - > htrd , buf , len , & rem ) ) < = - 1 )
{
HIO_DEBUG3 ( hio , " HTTS(%p) - feed error onto client htrd %p(%d) \n " , htts , sck , ( int ) sck - > hnd ) ;
goto oops ;
}
if ( rem > 0 )
{
HIO_DEBUG3 ( hio , " HTTS(%p) - excessive data after contents by client %p(%d) \n " , htts , sck , ( int ) sck - > hnd ) ;
if ( cli - > task )
{
/* TODO store this to client buffer. once the current resource is completed, arrange to call on_read() with it */
}
else
{
/* TODO: no resource in action. so feed one more time */
}
}
return 0 ;
oops :
if ( sck - > on_read = = client_on_read )
{
/* halt only if clinet_on_read() is the current handler.
* client_on_read ( ) can be chain - called by the overriding handler */
hio_dev_sck_halt ( sck ) ;
}
return 0 ; /* still return success here. instead call halt() */
}
static int client_on_write ( hio_dev_sck_t * sck , hio_iolen_t wrlen , void * wrctx , const hio_skad_t * dstaddr )
{
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( sck ) ;
hio_t * hio = sck - > hio ;
hio_svc_htts_t * htts = cli - > htts ;
hio_svc_htts_task_t * task = cli - > task ;
HIO_ASSERT ( hio , cli - > l_idx = = INVALID_LIDX ) ;
/* handle event if it's write by self */
if ( wrctx = = & htts_svr_wrctx )
{
if ( wrlen < = - 1 )
{
HIO_DEBUG3 ( hio , " HTTS(%p) - unable to write to client %p(%d) \n " , htts , sck , ( int ) sck - > hnd ) ;
hio_dev_sck_halt ( sck ) ;
}
else if ( wrlen = = 0 )
{
/* if connect: is keep-alive, this part may not be called */
task - > task_res_pending_writes - - ;
}
else
{
HIO_ASSERT ( hio , task - > task_res_pending_writes > 0 ) ;
task - > task_res_pending_writes - - ;
}
}
return 0 ;
}
static void client_on_disconnect ( hio_dev_sck_t * sck )
{
hio_t * hio = sck - > hio ;
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( sck ) ;
hio_svc_htts_t * htts = cli - > htts ;
hio_svc_htts_task_t * task = cli - > task ;
/* called if init_client() has swapped the on_disconnect handler successfully */
HIO_ASSERT ( hio , cli - > sck = = sck ) ;
HIO_ASSERT ( hio , cli - > l_idx = = INVALID_LIDX ) ;
HIO_DEBUG4 ( hio , " HTTS(%p) - task(t=%p,c=%p,csck=%p) - handling client socket disconnect \n " , htts , task , cli , sck ) ;
fini_client ( cli ) ;
HIO_DEBUG4 ( hio , " HTTS(%p) - task(t=%p,c=%p,csck=%p) - handled client socket disconnect \n " , htts , task , cli , sck ) ;
/* Note: after this callback, the actual device pointed to by 'sck' will be freed in the main loop. */
}
2020-08-01 15:56:53 +00:00
/* ------------------------------------------------------------------------ */
2023-03-18 20:04:32 +00:00
2020-08-02 16:07:42 +00:00
# define MAX_CLIENT_IDLE 10
2021-07-22 07:30:20 +00:00
static void halt_idle_clients ( hio_t * hio , const hio_ntime_t * now , hio_tmrjob_t * job )
2020-08-02 16:07:42 +00:00
{
/* TODO: this idle client detector is far away from being accurate.
2023-01-11 14:59:41 +00:00
* enhance htrd to specify timeout on feed ( ) and utilize it . . .
2020-08-02 16:07:42 +00:00
* and remove this timer job */
2021-07-22 07:30:20 +00:00
hio_svc_htts_t * htts = ( hio_svc_htts_t * ) job - > ctx ;
hio_svc_htts_cli_t * cli ;
hio_ntime_t t ;
2020-08-02 16:07:42 +00:00
2021-07-22 07:30:20 +00:00
static hio_ntime_t max_client_idle = { MAX_CLIENT_IDLE , 0 } ;
2020-08-02 16:07:42 +00:00
2021-07-22 07:30:20 +00:00
for ( cli = HIO_SVC_HTTS_CLIL_FIRST_CLI ( & htts - > cli ) ; ! HIO_SVC_HTTS_CLIL_IS_NIL_CLI ( & htts - > cli , cli ) ; cli = cli - > cli_next )
2020-08-02 16:07:42 +00:00
{
2023-01-11 15:41:01 +00:00
if ( ! cli - > task )
2020-08-02 16:07:42 +00:00
{
2021-07-22 07:30:20 +00:00
hio_ntime_t t ;
HIO_SUB_NTIME ( & t , now , & cli - > last_active ) ;
2020-08-02 16:07:42 +00:00
2023-01-11 14:59:41 +00:00
if ( HIO_CMP_NTIME ( & t , & max_client_idle ) > = 0 )
2020-08-02 16:07:42 +00:00
{
2022-10-08 07:47:55 +00:00
HIO_DEBUG4 ( hio , " HTTS(%p) - Halting idle client(%p,%p,%d) \n " , htts , cli , cli - > sck , ( int ) cli - > sck - > hnd ) ;
2021-07-22 07:30:20 +00:00
hio_dev_sck_halt ( cli - > sck ) ;
2020-08-02 16:07:42 +00:00
}
}
}
2021-07-22 07:30:20 +00:00
HIO_INIT_NTIME ( & t , MAX_CLIENT_IDLE , 0 ) ;
HIO_ADD_NTIME ( & t , & t , now ) ;
if ( hio_schedtmrjobat ( hio , & t , halt_idle_clients , & htts - > idle_tmridx , htts ) < = - 1 )
2020-08-02 16:07:42 +00:00
{
2021-07-22 07:30:20 +00:00
HIO_INFO1 ( hio , " HTTS(%p) - unable to reschedule idle client detector. continuting \n " , htts ) ;
2020-08-02 16:07:42 +00:00
}
}
2020-05-05 15:12:08 +00:00
/* ------------------------------------------------------------------------ */
2023-02-20 08:08:41 +00:00
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 )
2020-05-05 15:12:08 +00:00
{
2021-07-22 07:30:20 +00:00
hio_svc_htts_t * htts = HIO_NULL ;
2020-05-05 15:12:08 +00:00
union
{
2021-07-22 07:30:20 +00:00
hio_dev_sck_make_t m ;
hio_dev_sck_listen_t l ;
2020-05-05 15:12:08 +00:00
} info ;
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_t * cli ;
2021-08-06 03:23:48 +00:00
hio_oow_t i , noks ;
2023-01-11 14:59:41 +00:00
if ( HIO_UNLIKELY ( nbinds < = 0 ) )
2021-08-06 03:23:48 +00:00
{
hio_seterrnum ( hio , HIO_EINVAL ) ;
goto oops ;
}
2020-05-05 15:12:08 +00:00
2022-10-07 05:08:40 +00:00
htts = ( hio_svc_htts_t * ) hio_callocmem ( hio , HIO_SIZEOF ( * htts ) + xtnsize ) ;
2021-07-22 07:30:20 +00:00
if ( HIO_UNLIKELY ( ! htts ) ) goto oops ;
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
HIO_DEBUG1 ( hio , " HTTS - STARTING SERVICE %p \n " , htts ) ;
2021-07-22 07:30:20 +00:00
htts - > hio = hio ;
htts - > svc_stop = hio_svc_htts_stop ;
2020-05-20 16:14:36 +00:00
htts - > proc_req = proc_req ;
2021-07-22 07:30:20 +00:00
htts - > idle_tmridx = HIO_TMRIDX_INVALID ;
2020-05-05 15:12:08 +00:00
2023-02-20 08:08:41 +00:00
if ( fcgic_tmout )
{
htts - > fcgic_tmout_set = 1 ;
htts - > fcgic_tmout = * fcgic_tmout ;
}
2023-02-20 16:08:28 +00:00
htts - > becbuf = hio_becs_open ( hio , 0 , 256 ) ;
if ( HIO_UNLIKELY ( ! htts - > becbuf ) ) goto oops ;
2021-08-06 03:23:48 +00:00
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 ;
for ( i = 0 , noks = 0 ; i < nbinds ; i + + )
2020-05-05 15:12:08 +00:00
{
2021-08-06 03:23:48 +00:00
hio_dev_sck_t * sck ;
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
HIO_MEMSET ( & info , 0 , HIO_SIZEOF ( info ) ) ;
2021-08-17 07:00:22 +00:00
switch ( hio_skad_get_family ( & binds [ i ] . localaddr ) )
2021-08-06 03:23:48 +00:00
{
case HIO_AF_INET :
info . m . type = HIO_DEV_SCK_TCP4 ;
break ;
2023-01-11 14:59:41 +00:00
2021-08-06 03:23:48 +00:00
case HIO_AF_INET6 :
info . m . type = HIO_DEV_SCK_TCP6 ;
break ;
2023-01-11 14:59:41 +00:00
2021-08-06 03:23:48 +00:00
# if defined(HIO_AF_UNIX)
case HIO_AF_UNIX :
info . m . type = HIO_DEV_SCK_UNIX ;
break ;
# endif
case HIO_AF_QX :
info . m . type = HIO_DEV_SCK_QX ;
break ;
default :
/* ignore this */
2021-08-17 07:00:22 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - [%zu] unsupported bind address type %d \n " , htts , i , ( int ) hio_skad_get_family ( & binds [ i ] . localaddr ) ) ;
2021-08-06 03:23:48 +00:00
continue ;
}
2023-01-11 14:59:41 +00:00
/* the callback names(prefixed with listener_on_) are somewhat misleading because
* they are triggered on the client sockets because the accepted client sockets
* inherit them */
2021-08-06 03:23:48 +00:00
info . m . options = HIO_DEV_SCK_MAKE_LENIENT ;
info . m . on_write = listener_on_write ;
info . m . on_read = listener_on_read ;
info . m . on_connect = listener_on_connect ;
info . m . on_disconnect = listener_on_disconnect ;
sck = hio_dev_sck_make ( hio , HIO_SIZEOF ( * cli ) , & info . m ) ;
if ( HIO_UNLIKELY ( ! sck ) ) continue ;
2023-01-11 14:59:41 +00:00
2021-08-06 03:23:48 +00:00
/* the name 'cli' for the listening socket is awkward.
* the listening socket will use the htts , sck , and listening fields for tracking only .
* each accepted client socket gets the extension size for this size as well .
* most of other fields are used for client management . init_client ( ) will set
* the sck field to the client socket and the listening field to 0. */
cli = ( hio_svc_htts_cli_t * ) hio_dev_sck_getxtn ( sck ) ;
2022-10-08 07:47:55 +00:00
cli - > htts = htts ;
2021-08-06 03:23:48 +00:00
cli - > sck = sck ;
cli - > l_idx = i ;
if ( sck - > type ! = HIO_DEV_SCK_QX )
{
if ( hio_dev_sck_bind ( sck , & binds [ i ] ) < = - 1 )
{
if ( HIO_LOG_ENABLED ( hio , HIO_LOG_DEBUG ) )
{
hio_bch_t tmpbuf [ HIO_SKAD_IP_STRLEN + 1 ] ;
hio_skadtobcstr ( hio , & binds [ i ] . localaddr , tmpbuf , HIO_COUNTOF ( tmpbuf ) , HIO_SKAD_TO_BCSTR_ADDR | HIO_SKAD_TO_BCSTR_PORT ) ;
2021-08-10 10:32:36 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - [%zu] unable to bind to %hs \n " , htts , i , tmpbuf ) ;
2021-08-06 03:23:48 +00:00
}
hio_dev_sck_kill ( sck ) ;
continue ;
}
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
HIO_MEMSET ( & info , 0 , HIO_SIZEOF ( info ) ) ;
info . l . backlogs = 4096 ; /* TODO: use configuration? */
HIO_INIT_NTIME ( & info . l . accept_tmout , 5 , 1 ) ; /* usedd for ssl accept */
2023-01-11 14:59:41 +00:00
if ( hio_dev_sck_listen ( sck , & info . l ) < = - 1 )
2021-08-06 03:23:48 +00:00
{
if ( HIO_LOG_ENABLED ( hio , HIO_LOG_DEBUG ) )
{
hio_bch_t tmpbuf [ HIO_SKAD_IP_STRLEN + 1 ] ;
hio_skadtobcstr ( hio , & binds [ i ] . localaddr , tmpbuf , HIO_COUNTOF ( tmpbuf ) , HIO_SKAD_TO_BCSTR_ADDR | HIO_SKAD_TO_BCSTR_PORT ) ;
2021-08-10 10:32:36 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - [%zu] unable to bind to %hs \n " , htts , i , tmpbuf ) ;
2021-08-06 03:23:48 +00:00
}
hio_dev_sck_kill ( sck ) ;
goto oops ;
}
}
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
if ( HIO_LOG_ENABLED ( hio , HIO_LOG_DEBUG ) )
{
hio_skad_t tmpad ;
hio_bch_t tmpbuf [ HIO_SKAD_IP_STRLEN + 1 ] ;
hio_dev_sck_getsockaddr ( sck , & tmpad ) ;
hio_skadtobcstr ( hio , & tmpad , tmpbuf , HIO_COUNTOF ( tmpbuf ) , HIO_SKAD_TO_BCSTR_ADDR | HIO_SKAD_TO_BCSTR_PORT ) ;
2021-08-10 10:32:36 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - [%zu] listening on %hs \n " , htts , i , tmpbuf ) ;
2021-08-06 03:23:48 +00:00
}
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
htts - > l . sck [ i ] = sck ;
noks + + ;
2020-07-26 09:21:05 +00:00
}
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
if ( noks < = 0 ) goto oops ;
2023-01-11 14:59:41 +00:00
hio_fmttobcstr ( htts - > hio , htts - > server_name_buf , HIO_COUNTOF ( htts - > server_name_buf ) , " %s-%d.%d.%d " ,
2021-07-22 07:30:20 +00:00
HIO_PACKAGE_NAME , ( int ) HIO_PACKAGE_VERSION_MAJOR , ( int ) HIO_PACKAGE_VERSION_MINOR , ( int ) HIO_PACKAGE_VERSION_PATCH ) ;
2020-05-07 10:10:33 +00:00
htts - > server_name = htts - > server_name_buf ;
2021-07-22 07:30:20 +00:00
HIO_SVCL_APPEND_SVC ( & hio - > actsvc , ( hio_svc_t * ) htts ) ;
HIO_SVC_HTTS_CLIL_INIT ( & htts - > cli ) ;
2023-01-11 15:33:52 +00:00
HIO_SVC_HTTS_TASKL_INIT ( & htts - > task ) ;
2020-05-07 10:10:33 +00:00
2023-02-20 08:08:41 +00:00
htts - > fcgic = hio_svc_fcgic_start ( htts - > hio , ( htts - > fcgic_tmout_set ? & htts - > fcgic_tmout : HIO_NULL ) ) ;
2022-09-12 14:43:29 +00:00
if ( HIO_UNLIKELY ( ! htts - > fcgic ) )
{
/* TODO: only warning ... */
}
2021-08-06 03:23:48 +00:00
HIO_DEBUG1 ( hio , " HTTS - STARTED SERVICE %p \n " , htts ) ;
2020-08-02 16:07:42 +00:00
{
2021-07-22 07:30:20 +00:00
hio_ntime_t t ;
2020-08-02 16:07:42 +00:00
2021-07-22 07:30:20 +00:00
HIO_INIT_NTIME ( & t , MAX_CLIENT_IDLE , 0 ) ;
if ( hio_schedtmrjobafter ( hio , & t , halt_idle_clients , & htts - > idle_tmridx , htts ) < = - 1 )
2020-08-02 16:07:42 +00:00
{
2021-07-22 07:30:20 +00:00
HIO_INFO1 ( hio , " HTTS(%p) - unable to schedule idle client detector. continuting \n " , htts ) ;
2020-08-02 16:07:42 +00:00
/* don't care about failure */
}
}
2020-05-05 15:12:08 +00:00
return htts ;
oops :
if ( htts )
{
2022-09-12 14:43:29 +00:00
if ( htts - > fcgic )
{
hio_svc_fcgic_stop ( htts - > fcgic ) ;
htts - > fcgic = HIO_NULL ;
}
2023-01-11 14:59:41 +00:00
if ( htts - > l . sck )
2021-08-06 03:23:48 +00:00
{
for ( i = 0 ; i < htts - > l . count ; i + + )
2021-08-10 11:31:21 +00:00
{
if ( htts - > l . sck [ i ] ) hio_dev_sck_kill ( htts - > l . sck [ i ] ) ;
}
2021-08-06 03:23:48 +00:00
hio_freemem ( hio , htts - > l . sck ) ;
}
2023-02-20 16:08:28 +00:00
if ( htts - > becbuf ) hio_becs_close ( htts - > becbuf ) ;
2021-07-22 07:30:20 +00:00
hio_freemem ( hio , htts ) ;
2020-05-05 15:12:08 +00:00
}
2021-07-22 07:30:20 +00:00
return HIO_NULL ;
2020-05-05 15:12:08 +00:00
}
2021-07-22 07:30:20 +00:00
void hio_svc_htts_stop ( hio_svc_htts_t * htts )
2020-05-05 15:12:08 +00:00
{
2021-07-22 07:30:20 +00:00
hio_t * hio = htts - > hio ;
2021-08-06 03:23:48 +00:00
hio_oow_t i ;
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
HIO_DEBUG1 ( hio , " HTTS - STOPPING SERVICE %p \n " , htts ) ;
2020-05-07 10:10:33 +00:00
2022-09-12 14:43:29 +00:00
if ( htts - > fcgic )
{
hio_svc_fcgic_stop ( htts - > fcgic ) ;
htts - > fcgic = HIO_NULL ;
}
2023-01-11 14:59:41 +00:00
2021-08-06 03:23:48 +00:00
for ( i = 0 ; i < htts - > l . count ; i + + )
{
/* the socket may be null:
* if it has been destroyed for operation errors and forgotten in the disconnect callback thereafter
* if it has never been created successfully */
if ( htts - > l . sck [ i ] ) hio_dev_sck_kill ( htts - > l . sck [ i ] ) ;
}
2020-05-07 10:10:33 +00:00
2021-07-22 07:30:20 +00:00
while ( ! HIO_SVC_HTTS_CLIL_IS_EMPTY ( & htts - > cli ) )
2020-05-12 11:46:00 +00:00
{
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_t * cli = HIO_SVC_HTTS_CLIL_FIRST_CLI ( & htts - > cli ) ;
2023-03-18 20:04:32 +00:00
HIO_ASSERT ( hio , cli - > sck ! = HIO_NULL ) ;
2021-07-22 07:30:20 +00:00
hio_dev_sck_kill ( cli - > sck ) ;
2020-05-12 11:46:00 +00:00
}
2020-05-05 15:12:08 +00:00
2023-01-11 14:59:41 +00:00
while ( ! HIO_SVC_HTTS_TASKL_IS_EMPTY ( & htts - > task ) )
{
2023-01-11 15:41:01 +00:00
hio_svc_htts_task_t * task = HIO_SVC_HTTS_TASKL_FIRST_TASK ( & htts - > task ) ;
hio_svc_htts_task_kill ( task ) ;
2023-01-11 14:59:41 +00:00
}
2021-07-22 07:30:20 +00:00
HIO_SVCL_UNLINK_SVC ( htts ) ;
if ( htts - > server_name & & htts - > server_name ! = htts - > server_name_buf ) hio_freemem ( hio , htts - > server_name ) ;
2020-08-02 16:07:42 +00:00
2021-07-22 07:30:20 +00:00
if ( htts - > idle_tmridx ! = HIO_TMRIDX_INVALID ) hio_deltmrjob ( hio , htts - > idle_tmridx ) ;
2020-08-02 16:07:42 +00:00
2021-08-06 03:23:48 +00:00
if ( htts - > l . sck ) hio_freemem ( hio , htts - > l . sck ) ;
2023-01-11 14:59:41 +00:00
2023-02-20 16:08:28 +00:00
if ( htts - > becbuf ) hio_becs_close ( htts - > becbuf ) ;
2021-07-22 07:30:20 +00:00
hio_freemem ( hio , htts ) ;
2023-01-11 14:59:41 +00:00
HIO_DEBUG1 ( hio , " HTTS - STOPPED SERVICE %p \n " , htts ) ;
2020-05-05 15:12:08 +00:00
}
2022-10-07 05:08:40 +00:00
void * hio_svc_htts_getxtn ( hio_svc_htts_t * htts )
{
return ( void * ) ( htts + 1 ) ;
}
2021-07-22 07:30:20 +00:00
int hio_svc_htts_setservernamewithbcstr ( hio_svc_htts_t * htts , const hio_bch_t * name )
2020-05-07 10:10:33 +00:00
{
2021-07-22 07:30:20 +00:00
hio_t * hio = htts - > hio ;
hio_bch_t * tmp ;
2020-05-07 10:10:33 +00:00
2021-07-22 07:30:20 +00:00
if ( hio_copy_bcstr ( htts - > server_name_buf , HIO_COUNTOF ( htts - > server_name_buf ) , name ) = = hio_count_bcstr ( name ) )
2020-05-07 10:10:33 +00:00
{
tmp = htts - > server_name_buf ;
}
else
{
2021-07-22 07:30:20 +00:00
tmp = hio_dupbcstr ( hio , name , HIO_NULL ) ;
2020-05-07 10:10:33 +00:00
if ( ! tmp ) return - 1 ;
}
2021-07-22 07:30:20 +00:00
if ( htts - > server_name & & htts - > server_name ! = htts - > server_name_buf ) hio_freemem ( hio , htts - > server_name ) ;
2020-05-07 10:10:33 +00:00
htts - > server_name = tmp ;
return 0 ;
}
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
hio_dev_sck_t * hio_svc_htts_getlistendev ( hio_svc_htts_t * htts , hio_oow_t idx )
{
if ( idx > = htts - > l . count )
{
hio_seterrbfmt ( htts - > hio , HIO_EINVAL , " index out of range " ) ;
return HIO_NULL ;
}
if ( ! htts - > l . sck [ idx ] )
{
hio_seterrbfmt ( htts - > hio , HIO_EINVAL , " no listener at the given index " ) ;
return HIO_NULL ;
}
return htts - > l . sck [ idx ] ;
}
hio_oow_t hio_svc_htts_getnlistendevs ( hio_svc_htts_t * htts )
{
/* return the total number of listening socket devices.
* not all devices may be up and working */
return htts - > l . count ;
}
int hio_svc_htts_getsockaddr ( hio_svc_htts_t * htts , hio_oow_t idx , hio_skad_t * skad )
2021-07-16 02:30:25 +00:00
{
/* return the socket address of the listening socket. */
2021-08-06 03:23:48 +00:00
if ( idx > = htts - > l . count )
{
hio_seterrbfmt ( htts - > hio , HIO_EINVAL , " index out of range " ) ;
return - 1 ;
}
if ( ! htts - > l . sck [ idx ] )
{
hio_seterrbfmt ( htts - > hio , HIO_EINVAL , " no listener at the given index " ) ;
return - 1 ;
}
return hio_dev_sck_getsockaddr ( htts - > l . sck [ idx ] , skad ) ;
2021-07-16 02:30:25 +00:00
}
2020-05-08 09:48:26 +00:00
/* ----------------------------------------------------------------- */
2023-01-11 15:41:01 +00:00
/* task_size must be the total size to allocate including the header.
2022-10-07 05:08:40 +00:00
*
2023-01-11 15:41:01 +00:00
* For instance , if you define a task like below ,
2022-10-07 05:08:40 +00:00
*
2023-01-11 15:41:01 +00:00
* struct my_task_t
2022-10-07 05:08:40 +00:00
* {
2023-01-11 15:41:01 +00:00
* HIO_SVC_HTTS_TASK_HEADER ;
2022-10-07 05:08:40 +00:00
* int a ;
* int b ;
* } ;
*
2023-01-11 15:41:01 +00:00
* you can pass sizeof ( my_task_t ) to hio_svc_htts_task_make ( )
2022-10-07 05:08:40 +00:00
*/
2023-03-05 18:27:42 +00:00
hio_svc_htts_task_t * hio_svc_htts_task_make ( hio_svc_htts_t * htts , hio_oow_t task_size , hio_svc_htts_task_on_kill_t on_kill , hio_htre_t * req , hio_dev_sck_t * csck )
2020-05-07 15:47:33 +00:00
{
2021-07-22 07:30:20 +00:00
hio_t * hio = htts - > hio ;
2023-01-11 15:41:01 +00:00
hio_svc_htts_task_t * task ;
2023-03-04 15:55:15 +00:00
hio_oow_t qpath_len , qmth_len ;
2020-05-08 09:48:26 +00:00
2023-01-11 15:41:01 +00:00
HIO_DEBUG1 ( hio , " HTTS(%p) - allocating task \n " , htts ) ;
2023-01-11 14:59:41 +00:00
2023-03-04 15:55:15 +00:00
qpath_len = hio_htre_getqpathlen ( req ) ;
qmth_len = hio_htre_getqmethodlen ( req ) ;
task = hio_callocmem ( hio , task_size + qmth_len + 1 + qpath_len + 1 ) ;
2023-01-11 15:41:01 +00:00
if ( HIO_UNLIKELY ( ! task ) )
2023-01-11 14:59:41 +00:00
{
2023-01-11 15:41:01 +00:00
HIO_DEBUG1 ( hio , " HTTS(%p) - failed to allocate task \n " , htts ) ;
2023-01-11 14:59:41 +00:00
return HIO_NULL ;
}
2020-05-08 09:48:26 +00:00
2023-01-11 15:41:01 +00:00
task - > htts = htts ;
task - > task_size = task_size ;
task - > task_refcnt = 0 ;
task - > task_on_kill = on_kill ;
2023-03-09 16:27:08 +00:00
task - > task_csck = csck ;
task - > task_client = ( hio_svc_htts_cli_t * ) hio_dev_sck_getxtn ( csck ) ;
task - > task_keep_client_alive = ! ! ( req - > flags & HIO_HTRE_ATTR_KEEPALIVE ) ;
2023-03-04 15:55:15 +00:00
task - > task_req_qpath_ending_with_slash = ( hio_htre_getqpathlen ( req ) > 0 & & hio_htre_getqpath ( req ) [ hio_htre_getqpathlen ( req ) - 1 ] = = ' / ' ) ;
task - > task_req_qpath_is_root = ( hio_htre_getqpathlen ( req ) = = 1 & & hio_htre_getqpath ( req ) [ 0 ] = = ' / ' ) ;
2023-03-09 16:27:08 +00:00
task - > task_req_method = hio_htre_getqmethodtype ( req ) ;
task - > task_req_version = * hio_htre_getversion ( req ) ;
2023-03-18 20:04:32 +00:00
task - > task_req_conlen_unlimited = hio_htre_getreqcontentlen ( req , & task - > task_req_conlen ) ;
task - > task_req_flags = req - > flags ;
2023-03-04 15:55:15 +00:00
task - > task_req_qmth = ( hio_bch_t * ) ( ( hio_uint8_t * ) task + task_size ) ;
task - > task_req_qpath = task - > task_req_qmth + qmth_len + 1 ;
HIO_MEMCPY ( task - > task_req_qmth , hio_htre_getqmethodname ( req ) , qmth_len + 1 ) ;
HIO_MEMCPY ( task - > task_req_qpath , hio_htre_getqpath ( req ) , qpath_len + 1 ) ;
2020-05-08 09:48:26 +00:00
2023-03-18 20:04:32 +00:00
/* originally set to listener_on_write/listener_on_disconnect, but set to
* client_on_write / client_on_disconnect in init_client ( ) when the client socket is accepted */
HIO_ASSERT ( hio , csck - > on_read = = client_on_read ) ;
HIO_ASSERT ( hio , csck - > on_write = = client_on_write ) ;
HIO_ASSERT ( hio , csck - > on_disconnect = = client_on_disconnect ) ;
2023-01-11 15:41:01 +00:00
HIO_DEBUG2 ( hio , " HTTS(%p) - allocated task %p \n " , htts , task ) ;
return task ;
2020-05-08 09:48:26 +00:00
}
2023-01-11 15:41:01 +00:00
void hio_svc_htts_task_kill ( hio_svc_htts_task_t * task )
2020-05-08 09:48:26 +00:00
{
2023-01-11 15:41:01 +00:00
hio_svc_htts_t * htts = task - > htts ;
2023-01-11 14:59:41 +00:00
hio_t * hio = htts - > hio ;
2023-01-11 15:41:01 +00:00
HIO_DEBUG2 ( hio , " HTTS(%p) - destroying task %p \n " , htts , task ) ;
2023-01-11 14:59:41 +00:00
2023-01-11 15:41:01 +00:00
if ( task - > task_on_kill ) task - > task_on_kill ( task ) ;
hio_freemem ( hio , task ) ;
2023-01-11 14:59:41 +00:00
2023-01-11 15:41:01 +00:00
HIO_DEBUG2 ( hio , " HTTS(%p) - destroyed task %p \n " , htts , task ) ;
2020-05-08 09:48:26 +00:00
}
2023-03-10 17:32:33 +00:00
int hio_svc_htts_task_startreshdr ( hio_svc_htts_task_t * task , int status_code , const hio_bch_t * status_desc , int chunked )
{
hio_svc_htts_cli_t * cli = task - > task_client ;
hio_bch_t dtbuf [ 64 ] ;
HIO_ASSERT ( task - > htts - > hio , cli ! = HIO_NULL ) ;
2023-03-18 20:04:32 +00:00
HIO_ASSERT ( task - > htts - > hio , ! task - > task_res_started ) ;
HIO_ASSERT ( task - > htts - > hio , ! task - > task_res_ended ) ;
2023-03-10 17:32:33 +00:00
hio_svc_htts_fmtgmtime ( cli - > htts , HIO_NULL , dtbuf , HIO_COUNTOF ( dtbuf ) ) ;
if ( hio_becs_fmt ( cli - > sbuf , " HTTP/%d.%d " , task - > task_req_version . major , task - > task_req_version . minor ) = = ( hio_oow_t ) - 1 ) return - 1 ;
if ( hio_becs_fcat ( cli - > sbuf , " %d %hs \r \n " , status_code , ( status_desc ? status_desc : hio_http_status_to_bcstr ( status_code ) ) ) = = ( hio_oow_t ) - 1 ) return - 1 ;
if ( hio_becs_fcat ( cli - > sbuf , " Server: %hs \r \n Date: %hs \r \n " , cli - > htts - > server_name , dtbuf ) = = ( hio_oow_t ) - 1 ) return - 1 ;
if ( chunked & & hio_becs_cat ( cli - > sbuf , " Transfer-Encoding: chunked \r \n " ) = = ( hio_oow_t ) - 1 ) return - 1 ;
if ( hio_becs_cat ( cli - > sbuf , ( task - > task_keep_client_alive ? " Connection: keep-alive \r \n " : " Connection: close \r \n " ) ) = = ( hio_oow_t ) - 1 ) return - 1 ;
2023-03-18 20:04:32 +00:00
task - > task_res_chunked = chunked ;
task - > task_res_started = 1 ;
task - > task_status_code = status_code ;
2023-03-10 17:32:33 +00:00
return 0 ;
}
static int is_res_header_acceptable ( const hio_bch_t * key )
{
return hio_comp_bcstr ( key , " Status " , 1 ) ! = 0 & &
hio_comp_bcstr ( key , " Connection " , 1 ) ! = 0 & &
hio_comp_bcstr ( key , " Transfer-Encoding " , 1 ) ! = 0 & &
hio_comp_bcstr ( key , " Server " , 1 ) ! = 0 & &
hio_comp_bcstr ( key , " Date " , 1 ) ! = 0 ;
}
int hio_svc_htts_task_addreshdrs ( hio_svc_htts_task_t * task , const hio_bch_t * key , const hio_htre_hdrval_t * value )
{
hio_svc_htts_cli_t * cli = task - > task_client ;
2023-03-18 20:04:32 +00:00
2023-03-10 17:32:33 +00:00
HIO_ASSERT ( task - > htts - > hio , cli ! = HIO_NULL ) ;
2023-03-18 20:04:32 +00:00
HIO_ASSERT ( task - > htts - > hio , task - > task_res_started ) ;
HIO_ASSERT ( task - > htts - > hio , ! task - > task_res_ended ) ;
2023-03-10 17:32:33 +00:00
if ( ! is_res_header_acceptable ( key ) ) return 0 ; /* ignore it*/
while ( value )
{
if ( hio_becs_fcat ( cli - > sbuf , " %hs: %hs \r \n " , key , value - > ptr ) = = ( hio_oow_t ) - 1 ) return - 1 ;
value = value - > next ;
}
return 0 ;
}
int hio_svc_htts_task_addreshdr ( hio_svc_htts_task_t * task , const hio_bch_t * key , const hio_bch_t * value )
{
hio_svc_htts_cli_t * cli = task - > task_client ;
HIO_ASSERT ( task - > htts - > hio , cli ! = HIO_NULL ) ;
2023-03-18 20:04:32 +00:00
HIO_ASSERT ( task - > htts - > hio , task - > task_res_started ) ;
HIO_ASSERT ( task - > htts - > hio , ! task - > task_res_ended ) ;
2023-03-10 17:32:33 +00:00
if ( ! is_res_header_acceptable ( key ) ) return 0 ; /* just ignore it*/
if ( hio_becs_fcat ( cli - > sbuf , " %hs: %hs \r \n " , key , value ) = = ( hio_oow_t ) - 1 ) return - 1 ;
return 0 ;
}
int hio_svc_htts_task_addreshdrfmt ( hio_svc_htts_task_t * task , const hio_bch_t * key , const hio_bch_t * vfmt , . . . )
{
hio_svc_htts_cli_t * cli = task - > task_client ;
va_list ap ;
2023-03-18 20:04:32 +00:00
2023-03-10 17:32:33 +00:00
HIO_ASSERT ( task - > htts - > hio , cli ! = HIO_NULL ) ;
2023-03-18 20:04:32 +00:00
HIO_ASSERT ( task - > htts - > hio , task - > task_res_started ) ;
HIO_ASSERT ( task - > htts - > hio , ! task - > task_res_ended ) ;
2023-03-10 17:32:33 +00:00
if ( ! is_res_header_acceptable ( key ) ) return 0 ; /* just ignore it*/
if ( hio_becs_fcat ( cli - > sbuf , " %hs: " , key ) = = ( hio_oow_t ) - 1 ) return - 1 ;
va_start ( ap , vfmt ) ;
2023-03-18 20:04:32 +00:00
if ( hio_becs_vfcat ( cli - > sbuf , vfmt , ap ) = = ( hio_oow_t ) - 1 )
2023-03-10 17:32:33 +00:00
{
va_end ( ap ) ;
return - 1 ;
}
va_end ( ap ) ;
if ( hio_becs_cat ( cli - > sbuf , " \r \n " ) = = ( hio_oow_t ) - 1 ) return - 1 ;
return 0 ;
}
2023-03-11 03:54:36 +00:00
static int write_raw_to_client ( hio_svc_htts_task_t * task , const void * data , hio_iolen_t dlen )
{
HIO_ASSERT ( task - > htts - > hio , task - > task_client ! = HIO_NULL ) ;
HIO_ASSERT ( task - > htts - > hio , task - > task_csck ! = HIO_NULL ) ;
2023-03-18 20:04:32 +00:00
//HIO_DEBUG2 (task->htts->hio, "WR TO C[%.*hs]\n", dlen, data);
2023-03-11 03:54:36 +00:00
2023-03-18 20:04:32 +00:00
task - > task_res_ever_sent = 1 ;
task - > task_res_pending_writes + + ;
if ( hio_dev_sck_write ( task - > task_csck , data , dlen , & htts_svr_wrctx , HIO_NULL ) < = - 1 )
2023-03-11 03:54:36 +00:00
{
2023-03-18 20:04:32 +00:00
task - > task_res_pending_writes - - ;
2023-03-11 03:54:36 +00:00
return - 1 ;
}
return 0 ;
}
static int write_chunk_to_client ( hio_svc_htts_task_t * task , const void * data , hio_iolen_t dlen )
{
hio_iovec_t iov [ 3 ] ;
hio_bch_t lbuf [ 16 ] ;
hio_oow_t llen ;
HIO_ASSERT ( task - > htts - > hio , task - > task_client ! = HIO_NULL ) ;
HIO_ASSERT ( task - > htts - > hio , task - > task_csck ! = HIO_NULL ) ;
/* hio_fmt_uintmax_to_bcstr() null-terminates the output. only HIO_COUNTOF(lbuf) - 1
* is enough to hold ' \r ' and ' \n ' at the back without ' \0 ' . */
llen = hio_fmt_uintmax_to_bcstr ( lbuf , HIO_COUNTOF ( lbuf ) - 1 , dlen , 16 | HIO_FMT_UINTMAX_UPPERCASE , 0 , ' \0 ' , HIO_NULL ) ;
lbuf [ llen + + ] = ' \r ' ;
lbuf [ llen + + ] = ' \n ' ;
iov [ 0 ] . iov_ptr = lbuf ;
iov [ 0 ] . iov_len = llen ;
iov [ 1 ] . iov_ptr = ( void * ) data ;
iov [ 1 ] . iov_len = dlen ;
iov [ 2 ] . iov_ptr = " \r \n " ;
iov [ 2 ] . iov_len = 2 ;
2023-03-18 20:04:32 +00:00
//HIO_DEBUG2 (task->htts->hio, "WR(CHNK) TO C[%.*hs]\n", dlen, data);
2023-03-11 03:54:36 +00:00
2023-03-18 20:04:32 +00:00
task - > task_res_ever_sent = 1 ;
task - > task_res_pending_writes + + ;
if ( hio_dev_sck_writev ( task - > task_csck , iov , HIO_COUNTOF ( iov ) , & htts_svr_wrctx , HIO_NULL ) < = - 1 )
2023-03-11 03:54:36 +00:00
{
2023-03-18 20:04:32 +00:00
task - > task_res_pending_writes - - ;
2023-03-11 03:54:36 +00:00
return - 1 ;
}
return 0 ;
}
2023-03-18 20:04:32 +00:00
int hio_svc_htts_task_endreshdr ( hio_svc_htts_task_t * task )
{
hio_svc_htts_cli_t * cli = task - > task_client ;
HIO_ASSERT ( task - > htts - > hio , cli ! = HIO_NULL ) ;
HIO_ASSERT ( task - > htts - > hio , task - > task_res_started ) ;
HIO_ASSERT ( task - > htts - > hio , ! task - > task_res_ended ) ;
if ( hio_becs_cat ( cli - > sbuf , " \r \n " ) = = ( hio_oow_t ) - 1 ) return - 1 ;
if ( task - > task_csck & & write_raw_to_client ( task , HIO_BECS_PTR ( cli - > sbuf ) , HIO_BECS_LEN ( cli - > sbuf ) ) < = - 1 ) return - 1 ;
/*(force_close && fcgi_write_to_client(fcgi, HIO_NULL, 0) <= -1))? -1: 0;*/
return 0 ;
}
2023-03-11 03:54:36 +00:00
int hio_svc_htts_task_addresbody ( hio_svc_htts_task_t * task , const void * data , hio_iolen_t dlen )
{
2023-03-18 20:04:32 +00:00
if ( ! task - > task_csck ) return 0 ;
2023-03-11 03:54:36 +00:00
return task - > task_res_chunked ? write_chunk_to_client ( task , data , dlen ) : write_raw_to_client ( task , data , dlen ) ;
}
2023-03-25 18:01:40 +00:00
int hio_svc_htts_task_addresbodyfromfile ( hio_svc_htts_task_t * task , int fd , hio_foff_t foff , hio_iolen_t len )
{
if ( task - > task_csck )
{
task - > task_res_pending_writes + + ;
if ( hio_dev_sck_sendfile ( task - > task_csck , fd , foff , len , & htts_svr_wrctx ) < = - 1 )
{
task - > task_res_pending_writes - - ;
return - 1 ;
}
}
return 0 ;
}
2023-03-11 03:54:36 +00:00
int hio_svc_htts_task_endbody ( hio_svc_htts_task_t * task )
{
/* send the last chunk */
if ( ! task - > task_res_ended )
{
task - > task_res_ended = 1 ;
2023-03-18 20:04:32 +00:00
if ( ! task - > task_res_ever_sent )
{
if ( hio_svc_htts_task_sendfinalres ( task , HIO_HTTP_STATUS_INTERNAL_SERVER_ERROR , HIO_NULL , HIO_NULL , 0 ) < = - 1 ) return - 1 ;
}
else
2023-03-11 03:54:36 +00:00
{
2023-03-18 20:04:32 +00:00
if ( task - > task_csck & & task - > task_res_chunked & & write_raw_to_client ( task , " 0 \r \n \r \n " , 5 ) < = - 1 ) return - 1 ;
2023-03-11 03:54:36 +00:00
}
2023-03-18 20:04:32 +00:00
if ( task - > task_csck & & ! task - > task_keep_client_alive & & write_raw_to_client ( task , HIO_NULL , 0 ) < = - 1 ) return - 1 ;
2023-03-11 03:54:36 +00:00
}
2023-03-09 16:27:08 +00:00
return 0 ;
2023-03-04 15:55:15 +00:00
}
2023-03-18 20:04:32 +00:00
int hio_svc_htts_task_sendfinalres ( hio_svc_htts_task_t * task , int status_code , const hio_bch_t * content_type , const hio_bch_t * content_text , int force_close )
{
hio_svc_htts_t * htts = task - > htts ;
hio_t * hio = htts - > hio ;
hio_svc_htts_cli_t * cli = task - > task_client ;
hio_bch_t dtbuf [ 64 ] ;
hio_oow_t content_len ;
const hio_bch_t * status_msg ;
if ( HIO_UNLIKELY ( ! cli ) )
{
/* the client has probably been disconnected */
HIO_ASSERT ( hio , task - > task_csck = = HIO_NULL ) ;
return 0 ; /* no data */
}
status_msg = hio_http_status_to_bcstr ( status_code ) ;
hio_svc_htts_fmtgmtime ( task - > htts , HIO_NULL , dtbuf , HIO_COUNTOF ( dtbuf ) ) ;
if ( ! force_close ) force_close = ! task - > task_keep_client_alive ;
if ( hio_becs_fmt ( cli - > sbuf , " HTTP/%d.%d %d %hs \r \n Server: %hs \r \n Date: %hs \r \n Connection: %hs \r \n " ,
task - > task_req_version . major , task - > task_req_version . minor ,
status_code , status_msg ,
cli - > htts - > server_name , dtbuf ,
( force_close ? " close " : " keep-alive " ) ) = = ( hio_oow_t ) - 1 ) return - 1 ;
if ( ! content_text ) content_text = status_msg ;
if ( content_type & & hio_becs_fcat ( cli - > sbuf , " Content-Type: %hs \r \n " , content_type ) = = ( hio_oow_t ) - 1 ) return - 1 ;
content_len = hio_count_bcstr ( content_text ) ;
if ( task - > task_req_method = = HIO_HTTP_HEAD )
{
/* if status code is 200, the content is retained but the actual content is discarded. */
if ( status_code ! = HIO_HTTP_STATUS_OK ) content_len = 0 ;
content_text = " " ;
}
if ( status_code = = HIO_HTTP_STATUS_MOVED_PERMANENTLY | |
status_code = = HIO_HTTP_STATUS_MOVED_TEMPORARILY | |
status_code = = HIO_HTTP_STATUS_TEMPORARY_REDIRECT | |
status_code = = HIO_HTTP_STATUS_PERMANENT_REDIRECT )
{
/* don't send content body when the status code is 3xx. include the Location header only. */
if ( hio_becs_fcat ( cli - > sbuf , " Content-Length: 0 \r \n Location: %hs%hs \r \n \r \n " , task - > task_req_qpath , ( task - > task_req_qpath_ending_with_slash ? " " : " / " ) ) = = ( hio_oow_t ) - 1 ) return - 1 ;
}
else
{
if ( hio_becs_fcat ( cli - > sbuf , " Content-Length: %zu \r \n \r \n %hs " , content_len , content_text ) = = ( hio_oow_t ) - 1 ) return - 1 ;
}
task - > task_status_code = status_code ; /* remember the status code sent to the client. doesn't matter if it fails to write or not */
if ( write_raw_to_client ( task , HIO_BECS_PTR ( cli - > sbuf ) , HIO_BECS_LEN ( cli - > sbuf ) ) < = - 1 ) return - 1 ;
if ( force_close & & write_raw_to_client ( task , HIO_NULL , 0 ) < = - 1 ) return - 1 ;
return 1 ;
}
2023-03-28 16:24:20 +00:00
int hio_svc_htts_task_handleexpect100 ( hio_svc_htts_task_t * task )
2023-03-18 20:04:32 +00:00
{
# if !defined(TASK_ALLOW_UNLIMITED_REQ_CONTENT_LENGTH)
if ( task - > task_req_conlen_unlimited )
{
/* Transfer-Encoding is chunked. no content-length is known in advance. */
/* option 1. buffer contents. if it gets too large, send 413 Request Entity Too Large.
* option 2. send 411 Length Required immediately
* option 3. set Content - Length to - 1 and use EOF to indicate the end of content [ Non - Standard ] */
if ( hio_svc_htts_task_sendfinalres ( task , HIO_HTTP_STATUS_LENGTH_REQUIRED , HIO_NULL , HIO_NULL , 1 ) < = - 1 ) return - 1 ;
}
# endif
if ( task - > task_req_flags & HIO_HTRE_ATTR_EXPECT100 )
{
/* TODO: Expect: 100-continue? who should handle this? fcgi? or the http server? */
/* CAN I LET the fcgi SCRIPT handle this? */
if ( hio_comp_http_version_numbers ( & task - > task_req_version , 1 , 1 ) > = 0 & &
( task - > task_req_conlen_unlimited | | task - > task_req_conlen > 0 ) & &
( task - > task_req_method ! = HIO_HTTP_GET & & task - > task_req_method ! = HIO_HTTP_HEAD ) )
{
/*
* Don ' t send 100 Continue if http verions is lower than 1.1
* [ RFC7231 ]
* A server that receives a 100 - continue expectation in an HTTP / 1.0
* request MUST ignore that expectation .
*
* Don ' t send 100 Continue if expected content length is 0.
* [ RFC7231 ]
* A server MAY omit sending a 100 ( Continue ) response if it has
* already received some or all of the message body for the
* corresponding request , or if the framing indicates that there is
* no message body .
*/
hio_bch_t msgbuf [ 64 ] ;
hio_oow_t msglen ;
msglen = hio_fmttobcstr ( task - > htts - > hio , msgbuf , HIO_COUNTOF ( msgbuf ) , " HTTP/%d.%d %d %hs \r \n \r \n " , task - > task_req_version . major , task - > task_req_version . minor , HIO_HTTP_STATUS_CONTINUE , hio_http_status_to_bcstr ( HIO_HTTP_STATUS_CONTINUE ) ) ;
if ( task - > task_csck & & write_raw_to_client ( task , msgbuf , msglen ) < = - 1 ) return - 1 ;
task - > task_res_ever_sent = 0 ; /* reset this as it's polluted for 100 continue */
}
}
else if ( task - > task_req_flags & HIO_HTRE_ATTR_EXPECT )
{
/* 417 Expectation Failed */
hio_svc_htts_task_sendfinalres ( task , HIO_HTTP_STATUS_EXPECTATION_FAILED , HIO_NULL , HIO_NULL , 1 ) ;
return - 1 ;
}
return 0 ;
}
2020-05-16 19:12:10 +00:00
/* ----------------------------------------------------------------- */
2020-05-12 11:46:00 +00:00
2021-07-22 07:30:20 +00:00
int hio_svc_htts_doproxy ( hio_svc_htts_t * htts , hio_dev_sck_t * csck , hio_htre_t * req , const hio_bch_t * upstream )
2020-05-06 09:28:36 +00:00
{
2020-05-12 11:46:00 +00:00
#if 0
2020-05-08 09:48:26 +00:00
1. attempt to connect to the proxy target . . .
2023-01-11 14:59:41 +00:00
2. in the mean time ,
2021-07-22 07:30:20 +00:00
hio_dev_watch ( csck , HIO_DEV_WATCH_UPDATE , 0 ) ; /* no input, no output watching */
2020-05-08 09:48:26 +00:00
3. once connected ,
2021-07-22 07:30:20 +00:00
hio_dev_watch ( csck , HIO_DEV_WATCH_RENEW , HIO_DEV_EVENT_IN ) ; /* enable input watching. if needed, enable output watching */
2020-05-08 09:48:26 +00:00
4. start proxying
2020-05-10 16:20:39 +00:00
5. if one side is stalled , donot read from another side . . . let the kernel slow the connection . . .
2020-05-08 09:48:26 +00:00
i need to know how may bytes are pending for this .
2021-07-22 07:30:20 +00:00
if pending too high , disable read watching . . . hio_dev_watch ( csck , HIO_DEV_WATCH_RENEW , 0 ) ;
2020-05-08 09:48:26 +00:00
# endif
2020-05-12 11:46:00 +00:00
return 0 ;
}
2020-05-18 16:40:00 +00:00
/* ----------------------------------------------------------------- */
2021-07-22 07:30:20 +00:00
void hio_svc_htts_fmtgmtime ( hio_svc_htts_t * htts , const hio_ntime_t * nt , hio_bch_t * buf , hio_oow_t len )
2020-05-18 16:40:00 +00:00
{
2021-07-22 07:30:20 +00:00
hio_ntime_t now ;
2020-05-18 16:40:00 +00:00
2023-01-11 14:59:41 +00:00
if ( ! nt )
2020-05-18 16:40:00 +00:00
{
2021-07-22 07:30:20 +00:00
hio_sys_getrealtime ( htts - > hio , & now ) ;
2020-05-18 16:40:00 +00:00
nt = & now ;
}
2021-07-22 07:30:20 +00:00
hio_fmt_http_time_to_bcstr ( nt , buf , len ) ;
2020-05-18 16:40:00 +00:00
}
2020-05-08 09:48:26 +00:00
2021-07-22 07:30:20 +00:00
hio_bch_t * hio_svc_htts_dupmergepaths ( hio_svc_htts_t * htts , const hio_bch_t * base , const hio_bch_t * path )
2020-05-20 16:14:36 +00:00
{
2021-07-22 07:30:20 +00:00
hio_bch_t * xpath ;
const hio_bch_t * ta [ 4 ] ;
hio_oow_t idx = 0 ;
2020-05-20 16:14:36 +00:00
ta [ idx + + ] = base ;
if ( path [ 0 ] ! = ' \0 ' )
{
2023-01-02 07:01:50 +00:00
if ( base [ hio_count_bcstr ( base ) - 1 ] ! = ' / ' ) ta [ idx + + ] = " / " ;
2020-05-20 16:14:36 +00:00
ta [ idx + + ] = path ;
}
2021-07-22 07:30:20 +00:00
ta [ idx + + ] = HIO_NULL ;
xpath = hio_dupbcstrs ( htts - > hio , ta , HIO_NULL ) ;
if ( HIO_UNLIKELY ( ! xpath ) ) return HIO_NULL ;
2020-05-20 16:14:36 +00:00
2021-07-22 07:30:20 +00:00
hio_canon_bcstr_path ( xpath , xpath , 0 ) ;
2020-05-20 16:14:36 +00:00
return xpath ;
}
2021-08-06 03:23:48 +00:00
int hio_svc_htts_writetosidechan ( hio_svc_htts_t * htts , hio_oow_t idx , const void * dptr , hio_oow_t dlen )
2020-07-24 17:29:52 +00:00
{
2021-08-06 03:23:48 +00:00
if ( idx > = htts - > l . count )
{
2021-08-10 10:32:36 +00:00
/* don't set the error information - TODO: change hio_seterrbfmt thread-safe?
2023-01-11 14:59:41 +00:00
* hio_seterrbfmt ( htts - > hio , HIO_EINVAL , " index out of range " ) ; */
2021-08-10 10:32:36 +00:00
errno = EINVAL ;
2021-08-06 03:23:48 +00:00
return - 1 ;
}
if ( ! htts - > l . sck [ idx ] )
{
2023-01-11 14:59:41 +00:00
/* don't set the error information
2021-08-10 10:32:36 +00:00
* hio_seterrbfmt ( htts - > hio , HIO_EINVAL , " no listener at the given index " ) ; */
errno = EINVAL ;
2021-08-06 03:23:48 +00:00
return - 1 ;
}
return hio_dev_sck_writetosidechan ( htts - > l . sck [ idx ] , dptr , dlen ) ;
2020-07-24 17:29:52 +00:00
}