summaryrefslogtreecommitdiffstats
path: root/src/stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stream.c')
-rw-r--r--src/stream.c26
1 files changed, 21 insertions, 5 deletions
diff --git a/src/stream.c b/src/stream.c
index a3c0c93..e643a6d 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -537,7 +537,7 @@ struct stream *stream_new(struct session *sess, struct stconn *sc, struct buffer
s->res.analyse_exp = TICK_ETERNITY;
s->txn = NULL;
- s->hlua = NULL;
+ s->hlua[0] = s->hlua[1] = NULL;
s->resolv_ctx.requester = NULL;
s->resolv_ctx.hostname_dn = NULL;
@@ -649,8 +649,10 @@ void stream_free(struct stream *s)
flt_stream_stop(s);
flt_stream_release(s, 0);
- hlua_ctx_destroy(s->hlua);
- s->hlua = NULL;
+ hlua_ctx_destroy(s->hlua[0]);
+ hlua_ctx_destroy(s->hlua[1]);
+ s->hlua[0] = s->hlua[1] = NULL;
+
if (s->txn)
http_destroy_txn(s);
@@ -2367,7 +2369,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
/* shutdown(write) pending */
if (unlikely((scb->flags & (SC_FL_SHUT_DONE|SC_FL_SHUT_WANTED)) == SC_FL_SHUT_WANTED &&
- (!co_data(req) || (req->flags & CF_WRITE_TIMEOUT)))) {
+ ((!co_data(req) && !sc_ep_have_ff_data(scb)) || (req->flags & CF_WRITE_TIMEOUT)))) {
if (scf->flags & SC_FL_ERROR)
scb->flags |= SC_FL_NOLINGER;
sc_shutdown(scb);
@@ -2475,7 +2477,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
/* shutdown(write) pending */
if (unlikely((scf->flags & (SC_FL_SHUT_DONE|SC_FL_SHUT_WANTED)) == SC_FL_SHUT_WANTED &&
- (!co_data(res) || (res->flags & CF_WRITE_TIMEOUT)))) {
+ ((!co_data(res) && !sc_ep_have_ff_data(scf)) || (res->flags & CF_WRITE_TIMEOUT)))) {
sc_shutdown(scf);
}
@@ -2681,6 +2683,20 @@ void sess_change_server(struct stream *strm, struct server *newsrv)
{
struct server *oldsrv = strm->srv_conn;
+ /* Dynamic servers may be deleted during process lifetime. This
+ * operation is always conducted under thread isolation. Several
+ * conditions prevent deletion, one of them is if server streams list
+ * is not empty. sess_change_server() uses stream_add_srv_conn() to
+ * ensure the latter condition.
+ *
+ * A race condition could exist for stream which referenced a server
+ * instance (s->target) without registering itself in its server list.
+ * This is notably the case for SF_DIRECT streams which referenced a
+ * server earlier during process_stream(). However at this time the
+ * code is deemed safe as process_stream() cannot be rescheduled before
+ * invocation of sess_change_server().
+ */
+
if (oldsrv == newsrv)
return;