diff --git a/include/haproxy/http_client-t.h b/include/haproxy/http_client-t.h index 611d56829..df25de397 100644 --- a/include/haproxy/http_client-t.h +++ b/include/haproxy/http_client-t.h @@ -30,7 +30,12 @@ struct httpclient { unsigned int flags; /* other flags */ }; -#define HTTPCLIENT_F_ENDED 0x00000001 +/* Action (FA) to do */ +#define HTTPCLIENT_FA_STOP 0x00000001 /* stops the httpclient at the next IO handler call */ +#define HTTPCLIENT_FA_AUTOKILL 0x00000002 /* sets the applet to destroy the httpclient struct itself */ + +/* status (FS) */ +#define HTTPCLIENT_FS_ENDED 0x00010000 /* the httpclient is stopped */ /* States of the HTTP Client Appctx */ enum { diff --git a/include/haproxy/http_client.h b/include/haproxy/http_client.h index e4f6fb04c..c0d544781 100644 --- a/include/haproxy/http_client.h +++ b/include/haproxy/http_client.h @@ -4,6 +4,7 @@ #include void httpclient_destroy(struct httpclient *hc); +void httpclient_stop_and_destroy(struct httpclient *hc); struct httpclient *httpclient_new(void *caller, enum http_meth_t meth, struct ist url); struct appctx *httpclient_start(struct httpclient *hc); @@ -20,7 +21,7 @@ static inline int httpclient_data(struct httpclient *hc) /* Return 1 if the httpclient ended and won't receive any new data */ static inline int httpclient_ended(struct httpclient *hc) { - return !!(hc->flags & HTTPCLIENT_F_ENDED); + return !!(hc->flags & HTTPCLIENT_FS_ENDED); } #endif /* ! _HAPROXY_HTTCLIENT_H */ diff --git a/src/http_client.c b/src/http_client.c index 3ea86c21e..6055a01cc 100644 --- a/src/http_client.c +++ b/src/http_client.c @@ -228,7 +228,7 @@ static void hc_cli_release(struct appctx *appctx) struct httpclient *hc = appctx->ctx.cli.p0; /* Everything possible was printed on the CLI, we can destroy the client */ - httpclient_destroy(hc); + httpclient_stop_and_destroy(hc); return; } @@ -407,6 +407,27 @@ out: return NULL; } +/* + * This function tries to destroy the httpclient if it wasn't running. + * If it was running, stop the client and ask it to autodestroy itself. + * + * Once this fonction is used, all pointer sto the client must be removed + * + */ +void httpclient_stop_and_destroy(struct httpclient *hc) +{ + + /* The httpclient was already stopped, we can safely destroy it */ + if (hc->flags & HTTPCLIENT_FS_ENDED) { + httpclient_destroy(hc); + } else { + /* if the client wasn't stopped, ask for a stop and destroy */ + hc->flags |= (HTTPCLIENT_FA_AUTOKILL | HTTPCLIENT_FA_STOP); + if (hc->appctx) + appctx_wakeup(hc->appctx); + } +} + /* Free the httpclient */ void httpclient_destroy(struct httpclient *hc) { @@ -415,6 +436,10 @@ void httpclient_destroy(struct httpclient *hc) if (!hc) return; + + /* we should never destroy a client which was not stopped */ + BUG_ON(!httpclient_ended(hc)); + /* request */ istfree(&hc->req.url); b_free(&hc->req.buf); @@ -480,6 +505,11 @@ static void httpclient_applet_io_handler(struct appctx *appctx) while (1) { + + /* required to stop */ + if (hc->flags & HTTPCLIENT_FA_STOP) + goto end; + switch(appctx->st0) { case HTTPCLIENT_S_REQ: @@ -667,11 +697,17 @@ static void httpclient_applet_release(struct appctx *appctx) struct httpclient *hc = appctx->ctx.httpclient.ptr; /* mark the httpclient as ended */ - hc->flags |= HTTPCLIENT_F_ENDED; + hc->flags |= HTTPCLIENT_FS_ENDED; /* the applet is leaving, remove the ptr so we don't try to call it * again from the caller */ hc->appctx = NULL; + + /* destroy the httpclient when set to autotokill */ + if (hc->flags & HTTPCLIENT_FA_AUTOKILL) { + httpclient_destroy(hc); + } + return; }