implemented proxy peer connection caching experimentally

This commit is contained in:
hyung-hwan 2014-11-11 15:41:11 +00:00
parent f0fe04fef2
commit 643f84a8dd
7 changed files with 565 additions and 338 deletions

View File

@ -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,40 +450,6 @@ 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
{
@ -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;
@ -1415,6 +1438,7 @@ QSE_EXPORT void qse_httpd_removetimerevent (
qse_httpd_timer_index_t index
);
/* -------------------------------------------- */
#ifdef __cplusplus
}

View File

@ -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
httpd->opt.scb.peer.close (httpd, &proxy->peer);
}
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);
}
}
}
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,8 +2355,54 @@ static int task_main_proxy (
proxy->res_consumed = 0;
proxy->res_pending = 0;
/* 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)
{
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);
n = httpd->opt.scb.peer.open (httpd, proxy->peer);
if (n <= -1)
{
/* TODO: translate more error codes to http error codes... */
@ -2342,7 +2413,7 @@ static int task_main_proxy (
#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 open peer [%hs]\n", tmp);
}
#endif
@ -2350,17 +2421,18 @@ static int task_main_proxy (
goto oops;
}
#if defined(QSE_HTTPD_DEBUG)
#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);
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
}
#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;

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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