]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: applet: Notify the other side if data were consumed by an applet
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 27 Apr 2021 15:08:10 +0000 (17:08 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 28 Apr 2021 08:51:08 +0000 (10:51 +0200)
If an applet consumed output data (the amount of output data has changed
between before and after the call to the applet), the producer is
notified. It means CF_WRITE_PARTIAL and CF_WROTE_DATA are set on the output
channel and the opposite stream interface is notified some room was made in
its input buffer. This way, it is no longer the applet responsibility to
take care of it. However, it doesn't matter if the applet does the same.

Said like that, it looks like an improvement not a bug. But it really fixes
a bug in the lua, for HTTP applets. Indeed, applet:receive() and
applet:getline() are buggy for HTTP applets. Data are consumed but the
producer is not notified. It means if the payload is not fully received in
one time, the applet may be blocked because the producer remains blocked (it
is time dependent).

This patch must be backported as far as 2.0 (only for the HTX part).

src/applet.c

index a6d7f43fdde2922756978e9a60cc0752f1298db8..7d1ec289b00da03740224501355480585e823d64 100644 (file)
@@ -63,6 +63,7 @@ struct task *task_run_applet(struct task *t, void *context, unsigned int state)
        struct appctx *app = context;
        struct stream_interface *si = app->owner;
        unsigned int rate;
+       size_t count;
 
        if (app->state & APPLET_WANT_DIE) {
                __appctx_free(app);
@@ -85,8 +86,17 @@ struct task *task_run_applet(struct task *t, void *context, unsigned int state)
        if (!si_alloc_ibuf(si, &app->buffer_wait))
                si_rx_endp_more(si);
 
+       count = co_data(si_oc(si));
        app->applet->fct(app);
 
+       /* now check if the applet has released some room and forgot to
+        * notify the other side about it.
+        */
+       if (count != co_data(si_oc(si))) {
+               si_oc(si)->flags |= CF_WRITE_PARTIAL | CF_WROTE_DATA;
+               si_rx_room_rdy(si_opposite(si));
+       }
+
        /* measure the call rate and check for anomalies when too high */
        rate = update_freq_ctr(&app->call_rate, 1);
        if (rate >= 100000 && app->call_rate.prev_ctr && // looped more than 100k times over last second