Skip to content

in_http: Connection: close is parsed but never acted on, connection idles to the 10s timeout #12655

Open

Description

@arygupt

Bug Report

Describe the bug

Connection: close is parsed and recorded, but the connection is never closed in response to it. The response
does not carry Connection: close either, and the socket stays open until the 10 s IO timeout. A client that
sends Connection: close and waits for the close stalls for 10 seconds.

To Reproduce

POST / HTTP/1.1
Host: x
Content-Type: application/json
Connection: close
Content-Length: 7

{"a":1}

Measured: the 201 Created comes back at 0.00 s, the response has no Connection: close header, and EOF only
arrives at 10.6 s when the server times the connection out.

Root cause

The parser does record the intent — mk_http_parser.c:356 sets p->header_connection = MK_HTTP_PARSER_CONN_CLOSE,
and mk_http_keepalive_check() (mk_http.c:1135) turns that into cs->close_now = MK_TRUE.

But close_now is only ever acted on in mk_lib.c:769, which is the standalone monkey server path. The http
input plugin does not use mk_lib — it has its own connection handler, and plugins/in_http/http_conn.c only
initialises the flag:

session->close_now = MK_FALSE;      /* http_conn.c:201 — set, never read */

grep -c close_now plugins/in_http/http_conn.c is 1: the initialisation. Nothing in in_http ever reads it.

Expected behavior

After sending the response for a request with Connection: close, the server should close the connection (and
should include Connection: close in the response).

Your Environment

  • Fluent Bit 5.1.5 (fluent/fluent-bit:latest)
  • Linux, aarch64, official container image
  • Input: http plugin, default settings

Impact

Pre-auth. Every client that uses Connection: close — the default for many one-shot HTTP clients — pays a 10 s
stall waiting for a close that only comes from the server timeout. It also holds a connection slot for those 10 s.

Activity

  1. arygupt commented on Oct 25, 2026

    @arygupt
    Author

    For accuracy: the response itself is fine — it carries content-length: 0, so the message is properly delimited and a client is not left guessing where the body ends. The defect is only the missing close (and the missing Connection: close echo), which costs the 10 s stall.

  2. arygupt commented on Oct 25, 2026

    @arygupt
    Author

    Sharper root cause than my first description, and it also explains why HTTP/1.0 behaves differently.

    close_now is never set in this path. The only caller of mk_http_keepalive_check() — the function that turns the parsed header into cs->close_now = MK_TRUE — is mk_http_handler() in mk_http.c:186, which is the standalone monkey server. The http input plugin does not use mk_http_handler; it has its own handler in plugins/in_http/http_conn.c, and grep -c close_now plugins/in_http/http_conn.c is 1 — the initialisation to MK_FALSE. So for in_http the flag is always FALSE, and the if (cs->close_now == MK_TRUE) teardown in mk_http.c:1231 is never reached.

    Consistent with that: an HTTP/1.0 request does close immediately (EOF at 0.00 s), because the protocol branch sets close_now before the header block, and that path is reached. HTTP/1.1 with Connection: close does not, because the flag is set by a function in_http never calls.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions