implemented proxy peer connection caching experimentally
This commit is contained in:
parent
f0fe04fef2
commit
643f84a8dd
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user