diff --git a/qse/include/qse/http/httpd.h b/qse/include/qse/http/httpd.h index c568a4d2..758dac21 100644 --- a/qse/include/qse/http/httpd.h +++ b/qse/include/qse/http/httpd.h @@ -167,8 +167,13 @@ enum qse_httpd_peer_flag_t /* internal use only */ QSE_HTTPD_PEER_PENDING = (1 << 21), + /* internal use only */ + QSE_HTTPD_PEER_CACHED = (1 << 23), + /* all internal enumerators */ - QSE_HTTPD_PEER_ALL_INTERNALS = (QSE_HTTPD_PEER_CONNECTED | QSE_HTTPD_PEER_PENDING) + QSE_HTTPD_PEER_ALL_INTERNALS = (QSE_HTTPD_PEER_CONNECTED | + QSE_HTTPD_PEER_PENDING | + QSE_HTTPD_PEER_CACHED) }; typedef enum qse_httpd_peer_flag_t qse_httpd_peer_flag_t; @@ -176,10 +181,20 @@ typedef struct qse_httpd_peer_t qse_httpd_peer_t; struct qse_httpd_peer_t { int flags; /* 0 or bitwised-OR'ed of qse_httpd_peer_flag_t enumerators */ + qse_nwad_t nwad; qse_nwad_t local; /* local side address facing the peer */ + + /* peer.open can set these handles */ qse_httpd_hnd_t handle; qse_httpd_hnd_t handle2; + + /* peer links for the proxy peer cache list in client. + * internal use only. don't mess with these */ + qse_httpd_peer_t* next; + qse_httpd_peer_t* prev; + + qse_ntime_t timestamp; /* internal use only */ }; enum qse_httpd_mux_mask_t @@ -332,6 +347,42 @@ struct qse_httpd_scb_t int (*accept) (qse_httpd_t* httpd, qse_httpd_server_t* server, qse_httpd_client_t* client); } server; + struct + { + void (*close) ( + qse_httpd_t* httpd, + qse_httpd_client_t* client); + + void (*shutdown) ( + qse_httpd_t* httpd, + qse_httpd_client_t* client); + + /* action */ + qse_ssize_t (*recv) ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_mchar_t* buf, qse_size_t bufsize); + + qse_ssize_t (*send) ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + const qse_mchar_t* buf, qse_size_t bufsize); + + qse_ssize_t (*sendfile) ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_httpd_hnd_t handle, qse_foff_t* offset, qse_size_t count); + + /* event notification */ + int (*accepted) ( + qse_httpd_t* httpd, + qse_httpd_client_t* client); /* optional */ + void (*closed) ( + qse_httpd_t* httpd, + qse_httpd_client_t* client); /* optional */ + } client; + + struct { int (*open) (qse_httpd_t* httpd, qse_httpd_peer_t* peer); @@ -399,41 +450,7 @@ struct qse_httpd_scb_t qse_httpd_dirent_t* ent); } dir; - struct - { - void (*close) ( - qse_httpd_t* httpd, - qse_httpd_client_t* client); - - void (*shutdown) ( - qse_httpd_t* httpd, - qse_httpd_client_t* client); - - /* action */ - qse_ssize_t (*recv) ( - qse_httpd_t* httpd, - qse_httpd_client_t* client, - qse_mchar_t* buf, qse_size_t bufsize); - - qse_ssize_t (*send) ( - qse_httpd_t* httpd, - qse_httpd_client_t* client, - const qse_mchar_t* buf, qse_size_t bufsize); - - qse_ssize_t (*sendfile) ( - qse_httpd_t* httpd, - qse_httpd_client_t* client, - qse_httpd_hnd_t handle, qse_foff_t* offset, qse_size_t count); - - /* event notification */ - int (*accepted) ( - qse_httpd_t* httpd, - qse_httpd_client_t* client); /* optional */ - void (*closed) ( - qse_httpd_t* httpd, - qse_httpd_client_t* client); /* optional */ - } client; - + struct { /** opens the name resolution service. set this to #QSE_NULL to @@ -663,6 +680,12 @@ struct qse_httpd_client_t int initial_ifindex; /* == PRIVATE == */ + struct + { + qse_httpd_peer_t* first; + qse_httpd_peer_t* last; + } peer; /* list of proxy peers for this client */ + qse_htrd_t* htrd; int status; qse_httpd_task_trigger_t trigger; @@ -1404,9 +1427,9 @@ QSE_EXPORT qse_httpd_mod_t* qse_httpd_findmod ( /* -------------------------------------------- */ QSE_EXPORT int qse_httpd_inserttimerevent ( - qse_httpd_t* httpd, + qse_httpd_t* httpd, const qse_httpd_timer_event_t* event, - qse_httpd_timer_index_t* index + qse_httpd_timer_index_t* index ); @@ -1415,6 +1438,7 @@ QSE_EXPORT void qse_httpd_removetimerevent ( qse_httpd_timer_index_t index ); +/* -------------------------------------------- */ #ifdef __cplusplus } diff --git a/qse/lib/http/httpd-proxy.c b/qse/lib/http/httpd-proxy.c index 8591d7eb..935f7d6e 100644 --- a/qse/lib/http/httpd-proxy.c +++ b/qse/lib/http/httpd-proxy.c @@ -82,7 +82,8 @@ struct task_proxy_t qse_mchar_t* peer_name; qse_uint16_t peer_port; - qse_httpd_peer_t peer; + qse_httpd_peer_t* peer; /* it points to static_peer initially. it can get changed to something else */ + qse_httpd_peer_t static_peer; #define PROXY_PEER_OPEN (1 << 0) #define PROXY_PEER_CONNECTED (1 << 1) int peer_status; @@ -132,17 +133,19 @@ struct proxy_peer_htrd_xtn_t qse_httpd_task_t* task; }; -static void log_proxy_error (task_proxy_t* proxy, const qse_mchar_t* shortmsg) -{ -/* TODO: change this to HTTPD_DBGOUTXXXX */ - qse_httpd_act_t msg; - qse_size_t pos = 0; +/* ----------------------------------------------------------------- */ - msg.code = QSE_HTTPD_CATCH_MERRMSG; - pos += qse_mbsxcpy (&msg.u.merrmsg[pos], QSE_COUNTOF(msg.u.merrmsg) - pos, shortmsg); - pos += qse_nwadtombs (&proxy->peer.nwad, &msg.u.merrmsg[pos], QSE_COUNTOF(msg.u.merrmsg) - pos, QSE_NWADTOMBS_ALL); - proxy->httpd->opt.rcb.logact (proxy->httpd, &msg); -} +#if defined(QSE_HTTPD_DEBUG) + #define DBGOUT_PROXY_ERROR(proxy, msg) \ + do { \ + qse_mchar_t tmp1[128], tmp2[128]; \ + qse_nwadtombs (&(proxy)->peer->nwad, tmp1, QSE_COUNTOF(tmp1), QSE_NWADTOMBS_ALL); \ + qse_nwadtombs (&(proxy)->client->remote_addr, tmp2, QSE_COUNTOF(tmp2), QSE_NWADTOMBS_ALL); \ + HTTPD_DBGOUT3 ("Proxy error with peer [%hs] client [%hs] - %hs\n", tmp1, tmp2, msg); \ + } while(0) +#else + #define DBGOUT_PROXY_ERROR(proxy, msg) +#endif static int proxy_add_header_to_buffer ( task_proxy_t* proxy, qse_mbs_t* buf, const qse_mchar_t* key, const qse_htre_hdrval_t* val) @@ -705,9 +708,7 @@ static int proxy_htrd_peek_peer_output (qse_htrd_t* htrd, qse_htre_t* res) if ((proxy->resflags & PROXY_RES_PEER_LENGTH) && proxy->peer_output_received > proxy->peer_output_length) { - if (httpd->opt.trait & QSE_HTTPD_LOGACT) - log_proxy_error (proxy, "proxy redundant output - "); - + DBGOUT_PROXY_ERROR (proxy, "Redundant output from peer"); httpd->errnum = QSE_HTTPD_EINVAL; /* TODO: change it to a better error code */ return -1; } @@ -831,7 +832,7 @@ static void proxy_forward_client_input_to_peer (qse_httpd_t* httpd, qse_httpd_ta httpd->errnum = QSE_HTTPD_ENOERR; n = httpd->opt.scb.peer.send ( - httpd, &proxy->peer, + httpd, proxy->peer, QSE_MBS_PTR(proxy->reqfwdbuf), QSE_MBS_LEN(proxy->reqfwdbuf) ); @@ -840,8 +841,7 @@ static void proxy_forward_client_input_to_peer (qse_httpd_t* httpd, qse_httpd_ta { if (httpd->errnum != QSE_HTTPD_EAGAIN) { - if (httpd->opt.trait & QSE_HTTPD_LOGACT) - log_proxy_error (proxy, "proxy send-to-peer error - "); + DBGOUT_PROXY_ERROR (proxy, "Cannot send to peer"); proxy->reqflags |= PROXY_REQ_FWDERR; qse_mbs_clear (proxy->reqfwdbuf); @@ -902,7 +902,7 @@ static void adjust_peer_name_and_port (task_proxy_t* proxy) if (proxy->flags & PROXY_RAW) proxy->peer_port = QSE_HTTPD_DEFAULT_SECURE_PORT; else { - if (proxy->peer.flags & QSE_HTTPD_PEER_SECURE) + if (proxy->peer->flags & QSE_HTTPD_PEER_SECURE) proxy->peer_port = QSE_HTTPD_DEFAULT_SECURE_PORT; else proxy->peer_port = QSE_HTTPD_DEFAULT_PORT; @@ -947,9 +947,10 @@ static int task_init_proxy ( if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_X_FORWARDED) proxy->flags |= PROXY_X_FORWARDED; if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_ALLOW_UPGRADE) proxy->flags |= PROXY_ALLOW_UPGRADE; - if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_DST_SECURE) proxy->peer.flags |= QSE_HTTPD_PEER_SECURE; + proxy->peer = &proxy->static_peer; + if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_DST_SECURE) proxy->peer->flags |= QSE_HTTPD_PEER_SECURE; - proxy->peer.local = arg->rsrc->src.nwad; + proxy->peer->local = arg->rsrc->src.nwad; if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_DST_STR) { /* the destination given is a string. @@ -982,7 +983,7 @@ static int task_init_proxy ( } else { - proxy->peer.nwad = arg->rsrc->dst.nwad; + proxy->peer->nwad = arg->rsrc->dst.nwad; } if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_ENABLE_URS) @@ -1352,14 +1353,48 @@ static void task_fini_proxy ( if (proxy->peer_status & PROXY_PEER_OPEN) { - #if defined(QSE_HTTPD_DEBUG) + int reuse = 0; + + /* check if the peer connection can be reused */ + if (!(proxy->flags & (PROXY_RAW | PROXY_UPGRADE_REQUESTED | PROXY_PROTOCOL_SWITCHED)) && + !(proxy->resflags & PROXY_RES_PEER_CLOSE)) { - qse_mchar_t tmp[128]; - qse_nwadtombs (&proxy->peer.nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); - HTTPD_DBGOUT2 ("Closing peer [%hs] - %zd\n", tmp, (qse_size_t)proxy->peer.handle); + qse_mchar_t tmpch; + + /* check if the peer connection dropped connection or + * sending excessive data. don't reuse such a connection */ + if (httpd->opt.scb.peer.recv (httpd, proxy->peer, &tmpch, 1) <= -1 && + httpd->errnum == QSE_HTTPD_EAGAIN) reuse = 1; + } + + if (reuse && qse_httpd_cacheproxypeer (httpd, client, proxy->peer)) + { + /* cache a reusable peer connection */ + + #if defined(QSE_HTTPD_DEBUG) + qse_mchar_t tmp[128]; + + qse_nwadtombs (&proxy->peer->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); + HTTPD_DBGOUT2 ("Cached peer [%hs] - %zd\n", tmp, (qse_size_t)proxy->peer->handle); + #endif + } + else + { + #if defined(QSE_HTTPD_DEBUG) + qse_mchar_t tmp[128]; + + qse_nwadtombs (&proxy->peer->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); + HTTPD_DBGOUT2 ("Closing peer [%hs] - %zd\n", tmp, (qse_size_t)proxy->peer->handle); + #endif + + httpd->opt.scb.peer.close (httpd, proxy->peer); + + if (proxy->peer->flags & QSE_HTTPD_PEER_CACHED) + { + QSE_ASSERT (proxy->peer != &proxy->static_peer); + qse_httpd_freemem (httpd, proxy->peer); + } } - #endif - httpd->opt.scb.peer.close (httpd, &proxy->peer); } if ((proxy->flags & (PROXY_UPGRADE_REQUESTED | PROXY_PROTOCOL_SWITCHED)) == PROXY_UPGRADE_REQUESTED) @@ -1409,8 +1444,7 @@ printf ("task_main_proxy_5 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask if (httpd->errnum != QSE_HTTPD_EAGAIN) { /* can't return internal server error any more... */ - if (httpd->opt.trait & QSE_HTTPD_LOGACT) - log_proxy_error (proxy, "proxy send-to-client error - "); + DBGOUT_PROXY_ERROR (proxy, "Cannot send to client"); return -1; } } @@ -1448,7 +1482,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=% /* reading from the peer */ httpd->errnum = QSE_HTTPD_ENOERR; n = httpd->opt.scb.peer.recv ( - httpd, &proxy->peer, + httpd, proxy->peer, &proxy->buf[proxy->buflen], QSE_SIZEOF(proxy->buf) - proxy->buflen ); @@ -1457,8 +1491,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=% /* can't return internal server error any more... */ if (httpd->errnum != QSE_HTTPD_EAGAIN) { - if (httpd->opt.trait & QSE_HTTPD_LOGACT) - log_proxy_error (proxy, "proxy recv-from-peer error - "); + DBGOUT_PROXY_ERROR (proxy, "Cannot receive from peer"); return -1; } @@ -1473,8 +1506,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=% if (proxy->peer_output_received < proxy->peer_output_length) { - if (httpd->opt.trait & QSE_HTTPD_LOGACT) - log_proxy_error (proxy, "proxy premature eof(content) - "); + DBGOUT_PROXY_ERROR (proxy, "Premature content end"); return -1; } } @@ -1517,8 +1549,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=% if (proxy->peer_output_received > proxy->peer_output_length) { /* proxy returning too much data... something is wrong in PROXY */ - if (httpd->opt.trait & QSE_HTTPD_LOGACT) - log_proxy_error (proxy, "proxy redundant output - "); + DBGOUT_PROXY_ERROR (proxy, "Redundant output from peer"); return -1; } else if (proxy->peer_output_received == proxy->peer_output_length) @@ -1547,8 +1578,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=% if (httpd->errnum != QSE_HTTPD_EAGAIN) { /* can't return internal server error any more... */ - if (httpd->opt.trait & QSE_HTTPD_LOGACT) - log_proxy_error (proxy, "proxy send-to-client error - "); + DBGOUT_PROXY_ERROR (proxy, "Cannot send to client"); return -1; } } @@ -1559,7 +1589,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=% } } - if (proxy->peer.flags & QSE_HTTPD_PEER_PENDING) + if (proxy->peer->flags & QSE_HTTPD_PEER_PENDING) { /* this QSE_HTTPD_CLIENT_PENDING thing is a dirty hack for SSL. * In SSL, data is transmitted in a record. a record can be @@ -1620,8 +1650,7 @@ printf ("task_main_proxy_3 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask { if (httpd->errnum != QSE_HTTPD_EAGAIN) { - if (httpd->opt.trait & QSE_HTTPD_LOGACT) - log_proxy_error (proxy, "proxy send-to-client error - "); + DBGOUT_PROXY_ERROR (proxy, "Cannot send to client"); return -1; } } @@ -1709,8 +1738,7 @@ static int task_main_proxy_2 ( { if (httpd->errnum != QSE_HTTPD_EAGAIN) { - if (httpd->opt.trait & QSE_HTTPD_LOGACT) - log_proxy_error (proxy, "proxy send-to-client error - "); + DBGOUT_PROXY_ERROR (proxy, "Cannot send to client"); goto oops; } } @@ -1741,7 +1769,7 @@ static int task_main_proxy_2 ( /* there is something to read from peer */ httpd->errnum = QSE_HTTPD_ENOERR; n = httpd->opt.scb.peer.recv ( - httpd, &proxy->peer, + httpd, proxy->peer, &proxy->buf[proxy->buflen], QSE_SIZEOF(proxy->buf) - proxy->buflen ); @@ -1749,8 +1777,7 @@ static int task_main_proxy_2 ( { if (httpd->errnum != QSE_HTTPD_EAGAIN) { - if (httpd->opt.trait & QSE_HTTPD_LOGACT) - log_proxy_error (proxy, "proxy recv-from-peer error - "); + DBGOUT_PROXY_ERROR (proxy, "Cannot receive from peer"); goto oops; } } @@ -1760,9 +1787,7 @@ static int task_main_proxy_2 ( { /* end of output from peer before it has seen a header. * the proxy peer must be bad. */ - if (httpd->opt.trait & QSE_HTTPD_LOGACT) - log_proxy_error (proxy, "proxy premature eof(header) - "); - + DBGOUT_PROXY_ERROR (proxy, "Premature header end from peer"); if (!(proxy->resflags & PROXY_RES_RECEIVED_100)) http_errnum = 502; goto oops; } @@ -1782,8 +1807,7 @@ static int task_main_proxy_2 ( } /* premature eof from the peer */ - if (httpd->opt.trait & QSE_HTTPD_LOGACT) - log_proxy_error (proxy, "proxy no content(chunked) - "); + DBGOUT_PROXY_ERROR (proxy, "No chunked content from peer"); goto oops; } } @@ -1886,7 +1910,7 @@ static int task_main_proxy_1 ( int n; httpd->errnum = QSE_HTTPD_ENOERR; - n = httpd->opt.scb.peer.connected (httpd, &proxy->peer); + n = httpd->opt.scb.peer.connected (httpd, proxy->peer); if (n <= -1) { /* TODO: translate more error codes to http error codes... */ @@ -1898,7 +1922,7 @@ static int task_main_proxy_1 ( #if defined(QSE_HTTPD_DEBUG) { qse_mchar_t tmp[128]; - qse_nwadtombs (&proxy->peer.nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); + qse_nwadtombs (&proxy->peer->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); HTTPD_DBGOUT1 ("Cannnot connect to peer [%hs]\n", tmp); } #endif @@ -1982,11 +2006,11 @@ static void on_peer_name_resolved (qse_httpd_t* httpd, const qse_mchar_t* name, { /* resolved successfully */ - proxy->peer.nwad = *nwad; - qse_setnwadport (&proxy->peer.nwad, qse_hton16(proxy->peer_port)); + proxy->peer->nwad = *nwad; + qse_setnwadport (&proxy->peer->nwad, qse_hton16(proxy->peer_port)); - if (proxy->peer.local.type == QSE_NWAD_NX) - proxy->peer.local.type = proxy->peer.nwad.type; + if (proxy->peer->local.type == QSE_NWAD_NX) + proxy->peer->local.type = proxy->peer->nwad.type; proxy->flags |= PROXY_PEER_NAME_RESOLVED; } @@ -2006,7 +2030,7 @@ static void on_peer_name_resolved (qse_httpd_t* httpd, const qse_mchar_t* name, if (proxy->flags & PROXY_PEER_NAME_RESOLVED) { qse_mchar_t tmp[128]; - qse_nwadtombs (&proxy->peer.nwad, tmp, 128, QSE_NWADTOMBS_ALL); + qse_nwadtombs (&proxy->peer->nwad, tmp, 128, QSE_NWADTOMBS_ALL); HTTPD_DBGOUT2 ("Peer name [%hs] resolved to [%hs]\n", name, tmp); } #endif @@ -2039,7 +2063,7 @@ static void on_url_rewritten (qse_httpd_t* httpd, const qse_mchar_t* url, const qse_setnwadport (&nwad, qse_hton16(QSE_HTTPD_DEFAULT_PORT)); } - proxy->peer.nwad = nwad; + proxy->peer->nwad = nwad; proxy->flags |= PROXY_URL_REWRITTEN; proxy->flags &= ~PROXY_RESOLVE_PEER_NAME; /* skip dns */ } @@ -2139,9 +2163,9 @@ static void on_url_rewritten (qse_httpd_t* httpd, const qse_mchar_t* url, const /* TODO: antything todo when http is rewritten to HTTPS or vice versa */ if (proto_len == 8) - proxy->peer.flags |= QSE_HTTPD_PEER_SECURE; + proxy->peer->flags |= QSE_HTTPD_PEER_SECURE; else - proxy->peer.flags &= ~QSE_HTTPD_PEER_SECURE; + proxy->peer->flags &= ~QSE_HTTPD_PEER_SECURE; if (qse_mbstonwad (tmp, &nwad) <= -1) { @@ -2157,14 +2181,14 @@ static void on_url_rewritten (qse_httpd_t* httpd, const qse_mchar_t* url, const qse_setnwadport (&nwad, qse_hton16(proto_len == 8? QSE_HTTPD_DEFAULT_SECURE_PORT: QSE_HTTPD_DEFAULT_PORT)); } - proxy->peer.nwad = nwad; + proxy->peer->nwad = nwad; proxy->flags |= PROXY_URL_REWRITTEN; proxy->flags &= ~PROXY_RESOLVE_PEER_NAME; /* skip dns */ #if defined(QSE_HTTPD_DEBUG) { qse_mchar_t tmp[128]; - qse_nwadtombs (&proxy->peer.nwad, tmp, 128, QSE_NWADTOMBS_ALL); + qse_nwadtombs (&proxy->peer->nwad, tmp, 128, QSE_NWADTOMBS_ALL); HTTPD_DBGOUT4 ("Peer name resolved to [%hs] in url rewriting. new_url [%hs] %d %d\n", tmp, new_url, (int)proxy->qpath_pos_in_reqfwdbuf, @@ -2209,6 +2233,7 @@ static int task_main_proxy ( proxy_peer_htrd_xtn_t* xtn; int http_errnum = 500; int n; + qse_httpd_peer_t* peer_from_cache; if (proxy->flags & PROXY_INIT_FAILED) { @@ -2265,18 +2290,18 @@ static int task_main_proxy ( } if (proxy->dns_preresolve_mod && proxy->dns_preresolve_mod->dns_preresolve) - x = proxy->dns_preresolve_mod->dns_preresolve (proxy->dns_preresolve_mod, client, proxy->peer_name, &proxy->peer.nwad); + x = proxy->dns_preresolve_mod->dns_preresolve (proxy->dns_preresolve_mod, client, proxy->peer_name, &proxy->peer->nwad); else - x = httpd->opt.scb.dns.preresolve (httpd, client, proxy->peer_name, &proxy->peer.nwad); + x = httpd->opt.scb.dns.preresolve (httpd, client, proxy->peer_name, &proxy->peer->nwad); if (x <= -1) goto oops; if (x == 0) { - /* preresolve() indicates that proxy->peer.nwad contains the + /* preresolve() indicates that proxy->peer->nwad contains the * final address. no actual dns resolution is required */ proxy->flags |= PROXY_PEER_NAME_RESOLVED; proxy->flags &= ~PROXY_RESOLVE_PEER_NAME; - qse_setnwadport (&proxy->peer.nwad, qse_hton16(proxy->peer_port)); + qse_setnwadport (&proxy->peer->nwad, qse_hton16(proxy->peer_port)); } else { @@ -2330,37 +2355,84 @@ static int task_main_proxy ( proxy->res_consumed = 0; proxy->res_pending = 0; - httpd->errnum = QSE_HTTPD_ENOERR; - n = httpd->opt.scb.peer.open (httpd, &proxy->peer); - if (n <= -1) + /* get a cached peer connection */ + peer_from_cache = qse_httpd_decacheproxypeer (httpd, client, &proxy->peer->nwad, &proxy->peer->local, (proxy->peer->flags & QSE_HTTPD_PEER_SECURE)); + if (peer_from_cache) { - /* TODO: translate more error codes to http error codes... */ - if (httpd->errnum == QSE_HTTPD_ENOENT) http_errnum = 404; - else if (httpd->errnum == QSE_HTTPD_EACCES || - httpd->errnum == QSE_HTTPD_ECONN) http_errnum = 403; + qse_mchar_t tmpch; + + QSE_ASSERT (peer_from_cache->flags & QSE_HTTPD_PEER_CACHED); + + /* test if the cached connection is still ok */ + if (httpd->opt.scb.peer.recv (httpd, peer_from_cache, &tmpch, 1) <= -1 && + httpd->errnum == QSE_HTTPD_EAGAIN) + { + /* this connection seems to be ok. it didn't return EOF nor any data. + * A valid connection can't return data yes as no request has been sent.*/ + #if defined(QSE_HTTPD_DEBUG) + { + qse_mchar_t tmp[128]; + qse_nwadtombs (&peer_from_cache->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); + HTTPD_DBGOUT2 ("Decached peer [%hs] - %zd\n", tmp, (qse_size_t)peer_from_cache->handle); + } + #endif + } + else + { + /* the cached connection seems to be stale or invalid */ + #if defined(QSE_HTTPD_DEBUG) + { + qse_mchar_t tmp[128]; + qse_nwadtombs (&peer_from_cache->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); + HTTPD_DBGOUT2 ("Decached and closed stale peer [%hs] - %zd\n", tmp, (qse_size_t)peer_from_cache->handle); + } + #endif + httpd->opt.scb.peer.close (httpd, peer_from_cache); + qse_httpd_freemem (httpd, peer_from_cache); + + peer_from_cache = QSE_NULL; + } + } + + if (peer_from_cache) + { + proxy->peer = peer_from_cache; /* switch the peer pointer to the one acquired from the cache */ + n = 1; /* act as if it just got connected */ + } + else + { + httpd->errnum = QSE_HTTPD_ENOERR; + n = httpd->opt.scb.peer.open (httpd, proxy->peer); + if (n <= -1) + { + /* TODO: translate more error codes to http error codes... */ + if (httpd->errnum == QSE_HTTPD_ENOENT) http_errnum = 404; + else if (httpd->errnum == QSE_HTTPD_EACCES || + httpd->errnum == QSE_HTTPD_ECONN) http_errnum = 403; + + #if defined(QSE_HTTPD_DEBUG) + { + qse_mchar_t tmp[128]; + qse_nwadtombs (&proxy->peer->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); + HTTPD_DBGOUT1 ("Cannnot open peer [%hs]\n", tmp); + } + #endif + + goto oops; + } #if defined(QSE_HTTPD_DEBUG) { qse_mchar_t tmp[128]; - qse_nwadtombs (&proxy->peer.nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); - HTTPD_DBGOUT1 ("Cannnot open peer [%hs]\n", tmp); + qse_nwadtombs (&proxy->peer->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); + HTTPD_DBGOUT2 ("Opened peer [%hs] - %zd\n", tmp, (qse_size_t)proxy->peer->handle); } #endif - - goto oops; } -#if defined(QSE_HTTPD_DEBUG) - { - qse_mchar_t tmp[128]; - qse_nwadtombs (&proxy->peer.nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); - HTTPD_DBGOUT2 ("Opened peer [%hs] - %zd\n", tmp, (qse_size_t)proxy->peer.handle); - } -#endif - proxy->peer_status |= PROXY_PEER_OPEN; task->trigger.v[0].mask = QSE_HTTPD_TASK_TRIGGER_READ; - task->trigger.v[0].handle = proxy->peer.handle; + task->trigger.v[0].handle = proxy->peer->handle; /*task->trigger.cmask = QSE_HTTPD_TASK_TRIGGER_READ;*/ task->trigger.cmask = 0; diff --git a/qse/lib/http/httpd-std-dns.h b/qse/lib/http/httpd-std-dns.h index 4a6787de..5e472b20 100644 --- a/qse/lib/http/httpd-std-dns.h +++ b/qse/lib/http/httpd-std-dns.h @@ -814,10 +814,10 @@ static void tmr_dns_tmout_handle (qse_tmr_t* tmr, const qse_ntime_t* now, qse_tm *---------------------------------------------------------------- */ if (req->dns_retries > 0) { - httpd_xtn_t* httpd_xtn; + /*httpd_xtn_t* httpd_xtn;*/ qse_tmr_event_t tmout_event; - httpd_xtn = qse_httpd_getxtn (dc->httpd); + /*httpd_xtn = qse_httpd_getxtn (dc->httpd);*/ QSE_MEMSET (&tmout_event, 0, QSE_SIZEOF(tmout_event)); qse_gettime (&tmout_event.when); diff --git a/qse/lib/http/httpd-std-urs.h b/qse/lib/http/httpd-std-urs.h index 3ea9b241..ea9329e2 100644 --- a/qse/lib/http/httpd-std-urs.h +++ b/qse/lib/http/httpd-std-urs.h @@ -274,7 +274,7 @@ static void urs_close (qse_httpd_t* httpd, qse_httpd_urs_t* urs) static int urs_recv (qse_httpd_t* httpd, qse_httpd_urs_t* urs, qse_httpd_hnd_t handle) { urs_ctx_t* dc = (urs_ctx_t*)urs->ctx; - httpd_xtn_t* httpd_xtn; + /*httpd_xtn_t* httpd_xtn;*/ qse_skad_t fromaddr; qse_sck_len_t fromlen; @@ -285,9 +285,7 @@ static int urs_recv (qse_httpd_t* httpd, qse_httpd_urs_t* urs, qse_httpd_hnd_t h urs_req_t* req; qse_mchar_t* spc; -printf ("URS_RECV............................................\n"); - - httpd_xtn = qse_httpd_getxtn (httpd); + /*httpd_xtn = qse_httpd_getxtn (httpd);*/ /* TODO: use recvmsg with MSG_ERRQUEUE... set socket option IP_RECVERR... */ fromlen = QSE_SIZEOF(fromaddr); @@ -359,10 +357,10 @@ static void tmr_urs_tmout_handle (qse_tmr_t* tmr, const qse_ntime_t* now, qse_tm *---------------------------------------------------------------- */ if (req->urs_retries > 0) { - httpd_xtn_t* httpd_xtn; + /*httpd_xtn_t* httpd_xtn;*/ qse_tmr_event_t tmout_event; - httpd_xtn = qse_httpd_getxtn (dc->httpd); + /*httpd_xtn = qse_httpd_getxtn (dc->httpd);*/ QSE_MEMSET (&tmout_event, 0, QSE_SIZEOF(tmout_event)); qse_gettime (&tmout_event.when); diff --git a/qse/lib/http/httpd-std.c b/qse/lib/http/httpd-std.c index 22b8fdf4..67b04477 100644 --- a/qse/lib/http/httpd-std.c +++ b/qse/lib/http/httpd-std.c @@ -1134,6 +1134,192 @@ oops: /* ------------------------------------------------------------------- */ +static void client_close (qse_httpd_t* httpd, qse_httpd_client_t* client) +{ + qse_shutsckhnd (client->handle, QSE_SHUTSCKHND_RW); + qse_closesckhnd (client->handle); +} + +static void client_shutdown (qse_httpd_t* httpd, qse_httpd_client_t* client) +{ + qse_shutsckhnd (client->handle, QSE_SHUTSCKHND_RW); +} + +static qse_ssize_t client_recv ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + qse_mchar_t* buf, qse_size_t bufsize) +{ + if (client->status & QSE_HTTPD_CLIENT_SECURE) + { + #if defined(HAVE_SSL) + int ret = SSL_read (HANDLE_TO_SSL(client->handle2), buf, bufsize); + if (ret <= -1) + { + int err = SSL_get_error(HANDLE_TO_SSL(client->handle2),ret); + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) + qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN); + else + qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); + } + + if (SSL_pending (HANDLE_TO_SSL(client->handle2)) > 0) + client->status |= QSE_HTTPD_CLIENT_PENDING; + else + client->status &= ~QSE_HTTPD_CLIENT_PENDING; + + return ret; + #else + qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); + return -1; + #endif + } + else + { + qse_ssize_t ret; + ret = recv (client->handle, buf, bufsize, 0); + if (ret <= -1) qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); + return ret; + } +} + +static qse_ssize_t client_send ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + const qse_mchar_t* buf, qse_size_t bufsize) +{ + if (client->status & QSE_HTTPD_CLIENT_SECURE) + { + #if defined(HAVE_SSL) + int ret = SSL_write (HANDLE_TO_SSL(client->handle2), buf, bufsize); + if (ret <= -1) + { + int err = SSL_get_error(HANDLE_TO_SSL(client->handle2),ret); + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) + qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN); + else + qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); + } + return ret; + #else + qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); + return -1; + #endif + } + else + { + qse_ssize_t ret = send (client->handle, buf, bufsize, 0); + if (ret <= -1) qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); + return ret; + } +} + +static qse_ssize_t client_sendfile ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + qse_httpd_hnd_t handle, qse_foff_t* offset, qse_size_t count) +{ + if (client->status & QSE_HTTPD_CLIENT_SECURE) + { + return __send_file_ssl (httpd, (void*)client->handle2, handle, offset, count); + } + else + { + return __send_file (httpd, client->handle, handle, offset, count); + } +} + +static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client) +{ + if (client->status & QSE_HTTPD_CLIENT_SECURE) + { + #if defined(HAVE_SSL) + int ret; + SSL* ssl; + server_xtn_t* server_xtn; + + server_xtn = (server_xtn_t*)qse_httpd_getserverxtn (httpd, client->server); + + + if (!server_xtn->ssl_ctx) + { + /* performed the delayed ssl initialization */ + if (init_server_ssl (httpd, client->server) <= -1) return -1; + } + + QSE_ASSERT (server_xtn->ssl_ctx != QSE_NULL); + QSE_ASSERT (QSE_SIZEOF(client->handle2) >= QSE_SIZEOF(ssl)); + + if (HANDLE_TO_SSL(client->handle2)) + { + ssl = HANDLE_TO_SSL(client->handle2); + } + else + { + ssl = SSL_new (server_xtn->ssl_ctx); + if (ssl == QSE_NULL) + { + httpd->errnum = QSE_HTTPD_ESYSERR; + return -1; + } + + client->handle2 = SSL_TO_HANDLE(ssl); + if (SSL_set_fd (ssl, client->handle) == 0) + { + /* don't free ssl here since client_closed() + * will free it */ + httpd->errnum = QSE_HTTPD_ESYSERR; + return -1; + } + + SSL_set_read_ahead (ssl, 0); + } + + ret = SSL_accept (ssl); + if (ret <= 0) + { + int err = SSL_get_error(ssl, ret); + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) + { + /* handshaking isn't complete. */ + return 0; + } + + if (httpd->opt.trait & QSE_HTTPD_LOGACT) + { + qse_httpd_act_t msg; + msg.code = QSE_HTTPD_CATCH_MERRMSG; + ERR_error_string_n (err, msg.u.merrmsg, QSE_COUNTOF(msg.u.merrmsg)); + httpd->opt.rcb.logact (httpd, &msg); + } + + /* client_closed() free this. no SSL_free() here. + SSL_free (ssl); */ + return -1; + } + + #else + qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); + return -1; + #endif + } + + return 1; /* accept completed */ +} + +static void client_closed (qse_httpd_t* httpd, qse_httpd_client_t* client) +{ + if (client->status & QSE_HTTPD_CLIENT_SECURE) + { + #if defined(HAVE_SSL) + if ((SSL*)client->handle2) + { + SSL_shutdown ((SSL*)client->handle2); /* is this needed? */ + SSL_free ((SSL*)client->handle2); + } + #endif + } +} + +/* ------------------------------------------------------------------- */ + static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer) { /* -------------------------------------------------------------------- */ @@ -2130,193 +2316,6 @@ static int dir_read (qse_httpd_t* httpd, qse_httpd_hnd_t handle, qse_httpd_diren return 1; } -/* ------------------------------------------------------------------- */ - -static void client_close (qse_httpd_t* httpd, qse_httpd_client_t* client) -{ - qse_shutsckhnd (client->handle, QSE_SHUTSCKHND_RW); - qse_closesckhnd (client->handle); -} - -static void client_shutdown (qse_httpd_t* httpd, qse_httpd_client_t* client) -{ - qse_shutsckhnd (client->handle, QSE_SHUTSCKHND_RW); -} - -static qse_ssize_t client_recv ( - qse_httpd_t* httpd, qse_httpd_client_t* client, - qse_mchar_t* buf, qse_size_t bufsize) -{ - if (client->status & QSE_HTTPD_CLIENT_SECURE) - { - #if defined(HAVE_SSL) - int ret = SSL_read (HANDLE_TO_SSL(client->handle2), buf, bufsize); - if (ret <= -1) - { - int err = SSL_get_error(HANDLE_TO_SSL(client->handle2),ret); - if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) - qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN); - else - qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); - } - - if (SSL_pending (HANDLE_TO_SSL(client->handle2)) > 0) - client->status |= QSE_HTTPD_CLIENT_PENDING; - else - client->status &= ~QSE_HTTPD_CLIENT_PENDING; - - return ret; - #else - qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); - return -1; - #endif - } - else - { - qse_ssize_t ret; - ret = recv (client->handle, buf, bufsize, 0); - if (ret <= -1) qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); - return ret; - } -} - -static qse_ssize_t client_send ( - qse_httpd_t* httpd, qse_httpd_client_t* client, - const qse_mchar_t* buf, qse_size_t bufsize) -{ - if (client->status & QSE_HTTPD_CLIENT_SECURE) - { - #if defined(HAVE_SSL) - int ret = SSL_write (HANDLE_TO_SSL(client->handle2), buf, bufsize); - if (ret <= -1) - { - int err = SSL_get_error(HANDLE_TO_SSL(client->handle2),ret); - if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) - qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN); - else - qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); - } - return ret; - #else - qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); - return -1; - #endif - } - else - { - qse_ssize_t ret = send (client->handle, buf, bufsize, 0); - if (ret <= -1) qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); - return ret; - } -} - -static qse_ssize_t client_sendfile ( - qse_httpd_t* httpd, qse_httpd_client_t* client, - qse_httpd_hnd_t handle, qse_foff_t* offset, qse_size_t count) -{ - if (client->status & QSE_HTTPD_CLIENT_SECURE) - { - return __send_file_ssl (httpd, (void*)client->handle2, handle, offset, count); - } - else - { - return __send_file (httpd, client->handle, handle, offset, count); - } -} - -static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client) -{ - if (client->status & QSE_HTTPD_CLIENT_SECURE) - { - #if defined(HAVE_SSL) - int ret; - SSL* ssl; - server_xtn_t* server_xtn; - - server_xtn = (server_xtn_t*)qse_httpd_getserverxtn (httpd, client->server); - - - if (!server_xtn->ssl_ctx) - { - /* performed the delayed ssl initialization */ - if (init_server_ssl (httpd, client->server) <= -1) return -1; - } - - QSE_ASSERT (server_xtn->ssl_ctx != QSE_NULL); - QSE_ASSERT (QSE_SIZEOF(client->handle2) >= QSE_SIZEOF(ssl)); - - if (HANDLE_TO_SSL(client->handle2)) - { - ssl = HANDLE_TO_SSL(client->handle2); - } - else - { - ssl = SSL_new (server_xtn->ssl_ctx); - if (ssl == QSE_NULL) - { - httpd->errnum = QSE_HTTPD_ESYSERR; - return -1; - } - - client->handle2 = SSL_TO_HANDLE(ssl); - if (SSL_set_fd (ssl, client->handle) == 0) - { - /* don't free ssl here since client_closed() - * will free it */ - httpd->errnum = QSE_HTTPD_ESYSERR; - return -1; - } - - SSL_set_read_ahead (ssl, 0); - } - - ret = SSL_accept (ssl); - if (ret <= 0) - { - int err = SSL_get_error(ssl, ret); - if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) - { - /* handshaking isn't complete. */ - return 0; - } - - if (httpd->opt.trait & QSE_HTTPD_LOGACT) - { - qse_httpd_act_t msg; - msg.code = QSE_HTTPD_CATCH_MERRMSG; - ERR_error_string_n (err, msg.u.merrmsg, QSE_COUNTOF(msg.u.merrmsg)); - httpd->opt.rcb.logact (httpd, &msg); - } - - /* client_closed() free this. no SSL_free() here. - SSL_free (ssl); */ - return -1; - } - - #else - qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); - return -1; - #endif - } - - return 1; /* accept completed */ -} - -static void client_closed (qse_httpd_t* httpd, qse_httpd_client_t* client) -{ - if (client->status & QSE_HTTPD_CLIENT_SECURE) - { - #if defined(HAVE_SSL) - if ((SSL*)client->handle2) - { - SSL_shutdown ((SSL*)client->handle2); /* is this needed? */ - SSL_free ((SSL*)client->handle2); - } - #endif - } -} - - /* ------------------------------------------------------------------- */ #if 0 static qse_htb_walk_t walk (qse_htb_t* htb, qse_htb_pair_t* pair, void* ctx) @@ -2606,6 +2605,18 @@ static qse_httpd_scb_t httpd_system_callbacks = server_accept }, + /* client connection */ + { + client_close, + client_shutdown, + client_recv, + client_send, + client_sendfile, + client_accepted, + client_closed + }, + + /* proxy peer */ { peer_open, peer_close, @@ -2647,17 +2658,6 @@ static qse_httpd_scb_t httpd_system_callbacks = dir_read }, - /* client connection */ - { - client_close, - client_shutdown, - client_recv, - client_send, - client_sendfile, - client_accepted, - client_closed - }, - /* dns */ { dns_open, diff --git a/qse/lib/http/httpd.c b/qse/lib/http/httpd.c index f4c7765a..27d5481a 100644 --- a/qse/lib/http/httpd.c +++ b/qse/lib/http/httpd.c @@ -406,8 +406,7 @@ static qse_httpd_real_task_t* enqueue_task ( return new_task; } -static QSE_INLINE int dequeue_task ( - qse_httpd_t* httpd, qse_httpd_client_t* client) +static QSE_INLINE int dequeue_task (qse_httpd_t* httpd, qse_httpd_client_t* client) { qse_httpd_real_task_t* task; qse_size_t i; @@ -447,14 +446,134 @@ static QSE_INLINE int dequeue_task ( return 0; } -static QSE_INLINE void purge_tasks ( - qse_httpd_t* httpd, qse_httpd_client_t* client) +static QSE_INLINE void purge_tasks (qse_httpd_t* httpd, qse_httpd_client_t* client) { while (dequeue_task (httpd, client) == 0); } /* ----------------------------------------------------------------------- */ +static QSE_INLINE void unchain_cached_proxy_peer (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_peer_t* peer) +{ + QSE_ASSERT (peer->flags & QSE_HTTPD_PEER_CACHED); + + if (peer->next) peer->next->prev = peer->prev; + else client->peer.last = peer->prev; + + if (peer->prev) peer->prev->next = peer->next; + else client->peer.first = peer->next; +} + +static void purge_cached_proxy_peer (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_peer_t* peer) +{ + unchain_cached_proxy_peer (httpd, client, peer); + +#if defined(QSE_HTTPD_DEBUG) + { + qse_mchar_t tmp[128]; + + qse_nwadtombs (&peer->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); + HTTPD_DBGOUT2 ("Closing cached peer [%hs] - %zd\n", tmp, (qse_size_t)peer->handle); + } +#endif + + httpd->opt.scb.peer.close (httpd, peer); + qse_httpd_freemem (httpd, peer); +} + +static void purge_cached_proxy_peers (qse_httpd_t* httpd, qse_httpd_client_t* client) +{ + while (client->peer.first) + { + purge_cached_proxy_peer (httpd, client, client->peer.first); + } +} + +qse_httpd_peer_t* qse_httpd_cacheproxypeer (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_peer_t* tmpl) +{ + qse_httpd_peer_t* peer; + + if (tmpl->flags & QSE_HTTPD_PEER_CACHED) + { + /* If QSE_HTTPD_PEER_CACHED is set, tmpl points to a block allocated + * here previously. Link such a block to the cache list */ + peer = tmpl; + } + else + { + /* Clone the peer object if it's not previsouly allocated here */ + peer = qse_httpd_allocmem (httpd, QSE_SIZEOF(*peer)); + if (peer == QSE_NULL) goto oops; + + QSE_MEMCPY (peer, tmpl, QSE_SIZEOF(*peer)); + peer->flags |= QSE_HTTPD_PEER_CACHED; + } + + /* place the peer at the back of the peer list of a client */ + if (client->peer.last) + { + peer->next = QSE_NULL; + peer->prev = client->peer.last; + client->peer.last->next = peer; + client->peer.last = peer; + } + else + { + peer->next = QSE_NULL; + peer->prev = QSE_NULL; + client->peer.first = peer; + client->peer.last = peer; + } + + qse_gettime (&peer->timestamp); + return peer; + +oops: + if (peer) qse_httpd_freemem (httpd, peer); + return QSE_NULL; +} + +qse_httpd_peer_t* qse_httpd_decacheproxypeer ( + qse_httpd_t* httpd, qse_httpd_client_t* client, + const qse_nwad_t* nwad, const qse_nwad_t* local, int secure) +{ + qse_httpd_peer_t* peer, * next; + qse_ntime_t now, diff; + static qse_ntime_t diff_limit = { 5, 0 }; /* TODO: make this configurable */ + + qse_gettime (&now); + + peer = client->peer.first; + while (peer) + { + next = peer->next; + + qse_subtime (&now, &peer->timestamp, &diff); + if (qse_cmptime(&diff, &diff_limit) >= 0) + { + /* the entry is too old */ + purge_cached_proxy_peer (httpd, client, peer); + } + else if (qse_nwadequal (nwad, &peer->nwad) && qse_nwadequal (local, &peer->local)) + { + if ((secure && (peer->flags & QSE_HTTPD_PEER_SECURE)) || + (!secure && !(peer->flags & QSE_HTTPD_PEER_SECURE))) + { + unchain_cached_proxy_peer (httpd, client, peer); + peer->next = QSE_NULL; + peer->prev = QSE_NULL; + return peer; + } + } + + peer = next; + } + + return QSE_NULL; +} + + +/* ----------------------------------------------------------------------- */ static int htrd_peek_request (qse_htrd_t* htrd, qse_htre_t* req) { htrd_xtn_t* xtn = (htrd_xtn_t*) qse_htrd_getxtn (htrd); @@ -560,12 +679,12 @@ oops: return QSE_NULL; } -static void free_client ( - qse_httpd_t* httpd, qse_httpd_client_t* client) +static void free_client (qse_httpd_t* httpd, qse_httpd_client_t* client) { QSE_ASSERT (client->htrd != QSE_NULL); purge_tasks (httpd, client); + purge_cached_proxy_peers (httpd, client); qse_htrd_close (client->htrd); @@ -611,7 +730,7 @@ static void purge_client (qse_httpd_t* httpd, qse_httpd_client_t* client) { qse_mchar_t tmp[128]; qse_nwadtombs (&client->remote_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); - HTTPD_DBGOUT2 ("Purged client [%hs] - %zd\n", tmp, (qse_size_t)client->handle); + HTTPD_DBGOUT2 ("Purging client [%hs] - %zd\n", tmp, (qse_size_t)client->handle); } #endif diff --git a/qse/lib/http/httpd.h b/qse/lib/http/httpd.h index 3fe974ca..268ae289 100644 --- a/qse/lib/http/httpd.h +++ b/qse/lib/http/httpd.h @@ -192,6 +192,20 @@ void qse_httpd_remove_timer_event ( qse_tmr_index_t index ); +qse_httpd_peer_t* qse_httpd_cacheproxypeer ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + qse_httpd_peer_t* tmpl +); + +qse_httpd_peer_t* qse_httpd_decacheproxypeer ( + qse_httpd_t* httpd, + qse_httpd_client_t* client, + const qse_nwad_t* nwad, + const qse_nwad_t* local, + int secure +); + #ifdef __cplusplus } #endif