From da00880d491f34311f93a20b6b777bb940ab102f Mon Sep 17 00:00:00 2001 From: Staffan Olsson Date: Tue, 17 Feb 2026 08:09:56 +0100 Subject: [PATCH 1/2] fix fluentbit GCS uploads: patch header_lookup to match at line boundaries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCS responses include x-goog-stored-content-length before Content-Length. fluentbit's header_lookup() uses strcasestr("Content-Length: ") which matches the substring inside x-goog-stored-content-length, reading the stored object size instead of the response body length (typically 0). This causes the HTTP client to wait for bytes that never arrive, resulting in read timeouts and "broken connection" on every S3-to-GCS upload. The patch replaces the single strcasestr call with a loop that advances past any match not preceded by \n (or at buffer start), so only actual response header lines match. This is the minimal fix — no header parsing rewrite — and stays correct for standard HTTP where each header starts on its own line. Build args FLB_TRACE and FLB_HTTP_CLIENT_DEBUG default to Off for production; a separate debug-tagged image builds with both On. Co-Authored-By: Claude Opus 4.6 --- .github/workflows/fluentbit.yaml | 22 ++++++++++++++++++++ images/fluentbit/.dockerignore | 1 + images/fluentbit/Dockerfile | 7 +++++++ images/fluentbit/fix-gcs-header-lookup.patch | 22 ++++++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 images/fluentbit/fix-gcs-header-lookup.patch diff --git a/.github/workflows/fluentbit.yaml b/.github/workflows/fluentbit.yaml index 9fe8bf0..57ffaf6 100644 --- a/.github/workflows/fluentbit.yaml +++ b/.github/workflows/fluentbit.yaml @@ -6,10 +6,12 @@ on: paths: - .github/workflows/fluentbit.yaml - images/fluentbit/Dockerfile + - images/fluentbit/*.patch pull_request: paths: - .github/workflows/fluentbit.yaml - images/fluentbit/Dockerfile + - images/fluentbit/*.patch permissions: contents: read @@ -48,3 +50,23 @@ jobs: labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max + + - uses: docker/metadata-action@v5 + id: meta-debug + with: + images: ghcr.io/yolean/fluentbit + tags: | + type=raw,value=debug-${{ github.sha }} + + - uses: docker/build-push-action@v6 + with: + context: images/fluentbit + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name == 'push' }} + tags: ${{ steps.meta-debug.outputs.tags }} + labels: ${{ steps.meta-debug.outputs.labels }} + build-args: | + FLB_TRACE=On + FLB_HTTP_CLIENT_DEBUG=On + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/images/fluentbit/.dockerignore b/images/fluentbit/.dockerignore index 72e8ffc..ac26fc2 100644 --- a/images/fluentbit/.dockerignore +++ b/images/fluentbit/.dockerignore @@ -1 +1,2 @@ * +!*.patch diff --git a/images/fluentbit/Dockerfile b/images/fluentbit/Dockerfile index af3aef5..bc2a756 100644 --- a/images/fluentbit/Dockerfile +++ b/images/fluentbit/Dockerfile @@ -1,6 +1,8 @@ FROM debian:trixie@sha256:2c91e484d93f0830a7e05a2b9d92a7b102be7cab562198b984a84fdbc7806d91 AS build ARG FLB_VERSION=v4.2.2 +ARG FLB_TRACE=Off +ARG FLB_HTTP_CLIENT_DEBUG=Off RUN set -ex; \ export DEBIAN_FRONTEND=noninteractive; \ @@ -39,10 +41,15 @@ RUN set -ex; \ RUN git clone --depth 1 --branch $FLB_VERSION https://github.com/fluent/fluent-bit.git /src/fluent-bit +COPY *.patch /src/ +RUN cd /src/fluent-bit && git apply /src/*.patch + WORKDIR /src/fluent-bit/build RUN cmake \ -DFLB_RELEASE=On \ + -DFLB_TRACE=${FLB_TRACE} \ + -DFLB_HTTP_CLIENT_DEBUG=${FLB_HTTP_CLIENT_DEBUG} \ -DFLB_JEMALLOC=On \ -DFLB_TLS=On \ -DFLB_SHARED_LIB=Off \ diff --git a/images/fluentbit/fix-gcs-header-lookup.patch b/images/fluentbit/fix-gcs-header-lookup.patch new file mode 100644 index 0000000..b0dfe0f --- /dev/null +++ b/images/fluentbit/fix-gcs-header-lookup.patch @@ -0,0 +1,22 @@ +diff --git a/src/flb_http_client.c b/src/flb_http_client.c +--- a/src/flb_http_client.c ++++ b/src/flb_http_client.c +@@ -477,8 +477,16 @@ static int header_lookup(struct flb_http_client *c, + return FLB_HTTP_MORE; + } + +- /* Lookup the beginning of the header */ +- p = strcasestr(c->resp.data, header); ++ /* Lookup the beginning of the header, ensuring it starts a line. ++ * GCS returns x-goog-stored-content-length before Content-Length; ++ * strcasestr matches "Content-Length" inside the longer header name. */ ++ p = c->resp.data; ++ while ((p = strcasestr(p, header)) != NULL) { ++ if (p == c->resp.data || *(p - 1) == '\n') { ++ break; ++ } ++ p++; ++ } + end = strstr(c->resp.data, "\r\n\r\n"); + if (!p) { + if (end) { From 899f0e90e0ead7e4aacdfad3d51fe3af087ce30e Mon Sep 17 00:00:00 2001 From: Staffan Olsson Date: Tue, 17 Feb 2026 08:16:44 +0100 Subject: [PATCH 2/2] current distroless trixie --- images/fluentbit/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/images/fluentbit/Dockerfile b/images/fluentbit/Dockerfile index bc2a756..a321ce5 100644 --- a/images/fluentbit/Dockerfile +++ b/images/fluentbit/Dockerfile @@ -87,7 +87,7 @@ RUN set -ex; \ done; \ ls "$LIBDIR" -FROM gcr.io/distroless/cc-debian13:nonroot@sha256:5c94e1d2e831f0fadfe4048427f6ff3a91481606da2841c5b26674220ac84d2d +FROM gcr.io/distroless/cc-debian13:nonroot@sha256:84fcd3c223b144b0cb6edc5ecc75641819842a9679a3a58fd6294bec47532bf7 COPY --from=build /fluent-bit/bin/fluent-bit /usr/local/bin/ COPY --from=build /fluent-bit/etc/ /fluent-bit/etc/