]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: spoe: Improve error detection in SPOE applet on client abort
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 26 Aug 2025 13:49:15 +0000 (15:49 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Tue, 26 Aug 2025 14:12:18 +0000 (16:12 +0200)
It is possible to interrupt a SPOE applet without reporting an error. For
instance, when the client of the parent stream aborts. Thanks to this patch,
we take care to report an error on the SPOE applet to be sure to interrupt
the processing. It is especially important if the connection to the agent is
queued. Thanks to 886a248be ("BUG/MEDIUM: mux-spop: Reject connection
attempts from a non-spop frontend"), it is no longer an issue. But there is
no reason to continue to process if the parent stream is gone.

In addition, in the SPOE filter, if the processing is interrupted when the
filter is destroyed, no specific status code was set. It is not a big deal
because it cannot be logged at this stage. But it can be used to notify the SPOE
applet. So better to set it.

This patch should be backported as far as 3.1.

src/flt_spoe.c

index 371037129bea56198b065db819d8daf97f0af657..a1147665ab77acc83a2350178c93b83172f9d1b0 100644 (file)
@@ -434,6 +434,7 @@ static void spoe_release_appctx(struct appctx *appctx)
        /* Shutdown the server connection, if needed */
        if (appctx->st0 != SPOE_APPCTX_ST_END) {
                appctx->st0 = SPOE_APPCTX_ST_END;
+               applet_set_error(appctx);
                if (spoe_appctx->status_code == SPOP_ERR_NONE)
                        spoe_appctx->status_code = SPOP_ERR_IO;
        }
@@ -504,14 +505,15 @@ static void spoe_handle_appctx(struct appctx *appctx)
                goto out;
        }
 
-       if (!SPOE_APPCTX(appctx)->spoe_ctx)
-               appctx->st0 =  SPOE_APPCTX_ST_EXIT;
-
   switchstate:
        switch (appctx->st0) {
                /* case SPOE_APPCTX_ST_PROCESSING: */
                case SPOE_APPCTX_ST_WAITING_ACK:
-                       if (!spoe_handle_receiving_frame_appctx(appctx))
+                       if (!SPOE_APPCTX(appctx)->spoe_ctx) {
+                               appctx->st0 = SPOE_APPCTX_ST_END;
+                               applet_set_error(appctx);
+                       }
+                       else if (!spoe_handle_receiving_frame_appctx(appctx))
                                break;
                        goto switchstate;
 
@@ -1184,6 +1186,10 @@ static void spoe_destroy_context(struct filter *filter)
        if (!ctx)
                return;
 
+       if (ctx->state != SPOE_CTX_ST_NONE || ctx->state == SPOE_CTX_ST_READY) {
+               ctx->status_code = SPOE_CTX_ERR_INTERRUPT;
+               _HA_ATOMIC_INC(&conf->agent->counters.nb_errors);
+       }
        spoe_stop_processing(conf->agent, ctx);
        pool_free(pool_head_spoe_ctx, ctx);
        filter->ctx = NULL;