Skip to content

fix: two-layer gzip decompression for all inbound routes#160

Open
SudipSinha wants to merge 1 commit into
mainfrom
fix/gzip-middleware-all-paths
Open

fix: two-layer gzip decompression for all inbound routes#160
SudipSinha wants to merge 1 commit into
mainfrom
fix/gzip-middleware-all-paths

Conversation

@SudipSinha

@SudipSinha SudipSinha commented Jun 4, 2026

Copy link
Copy Markdown
Member

Summary

Fixes gzip decompression for KServe inference payloads across all three inbound paths:

  • /data/upload (FastAPI)
  • /consumer/kserve/v2 (FastAPI)
  • CloudEvent consumer (POST /) (FastAPI)

Mirrors the two-layer fix from Java TrustyAI service: trustyai-explainability/trustyai-explainability#707

Problem

TrustyAI fails to parse gzip-compressed inference payloads from KServe logger sidecar with error:

JSONDecodeError: Expecting value: line 1 column 1 (char 0)

The gzip magic bytes 0x1F 0x8B are being parsed as JSON. The initial gzip middleware was scoped only to /data/upload, leaving two paths uncovered:

  1. /consumer/kserve/v2 — FastAPI endpoint but outside middleware scope
  2. CloudEvent consumer (POST /) — Knative Eventing bypasses standard HTTP middleware

Design Philosophy

HTTP Content-Encoding is a transport-layer concern, not an application-layer concern. Handling it per-endpoint creates coverage gaps — every new endpoint becomes vulnerable by default until someone remembers to add decompression.

The correct approach is layered defense:

  1. Transport layer first: Enable middleware-level decompression to handle all HTTP requests before they reach endpoint handlers

  2. Application layer fallback: When a framework bypasses the transport layer (Knative Eventing strips Content-Encoding header but leaves body gzipped), add endpoint-specific decompression as a safety net

This ensures:

  • New endpoints are secure by default (middleware handles them)
  • Framework-specific edge cases are covered (application layer catches what middleware misses)
  • No per-endpoint boilerplate

Solution

Two-layer fix:

  1. Middleware layer (FastAPI endpoints):

    • Change GzipRequestMiddleware.DEFAULT_PATHS from ("/data/upload",) to ("*",)
    • All routes now get automatic gzip decompression
  2. Application layer (CloudEvent endpoints):

    • Add decompress_if_gzip() utility in src/endpoints/consumer/gzip_utils.py
    • Magic byte detection (0x1F 0x8B)
    • 100MB decompression bomb guard
    • Graceful fallback on malformed payloads
    • Called from CloudEvent consumer when Content-Encoding header is missing

Changes

File Change
src/middleware/gzip_middleware.py Changed DEFAULT_PATHS to ("*",)
src/endpoints/consumer/gzip_utils.py +59 lines (gzip detection + bomb guard)
src/endpoints/consumer/consumer_endpoint.py +30 lines (CloudEvent gzip handling)
src/endpoints/data/data_upload.py Removed explicit path from middleware call
tests/middleware/test_gzip_middleware_unit.py +45 lines (parametrized route tests)
tests/endpoints/consumer/test_cloud_event_gzip.py +92 lines (4 CloudEvent tests)

Net: +245 / -24 lines

Test Plan

  • uv run pytest tests/middleware/test_gzip_middleware_unit.py -v - All tests pass
  • uv run pytest tests/endpoints/consumer/test_cloud_event_gzip.py -v - All tests pass
  • Verify middleware decompresses on all routes (/data/upload, /consumer/kserve/v2, /)
  • Verify CloudEvent endpoint handles gzip body without Content-Encoding header
  • Cluster validation pending

Related


🤖 Generated with Claude Code

@SudipSinha SudipSinha self-assigned this Jun 4, 2026
@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@SudipSinha, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 24 minutes and 53 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5ba6d5b5-a0c7-4e96-a74d-55d7d05f01e1

📥 Commits

Reviewing files that changed from the base of the PR and between eeca7e6 and 9e39299.

📒 Files selected for processing (6)
  • src/endpoints/consumer/consumer_endpoint.py
  • src/endpoints/consumer/gzip_utils.py
  • src/endpoints/data/data_upload.py
  • src/middleware/gzip_middleware.py
  • tests/endpoints/consumer/test_cloud_event_gzip.py
  • tests/middleware/test_gzip_middleware_unit.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/gzip-middleware-all-paths

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@SudipSinha SudipSinha force-pushed the fix/gzip-middleware-all-paths branch 3 times, most recently from 8227c5c to 4639c6e Compare June 8, 2026 19:36
@SudipSinha SudipSinha marked this pull request as ready for review June 8, 2026 22:07
@SudipSinha SudipSinha added bug Something isn't working python Pull requests that update python code ok-to-test Proceed with CI testing tests high-priority Critical issues that should be addressed soon technical-debt Code that works but needs improvement (untested, deprecated patterns, etc.) labels Jun 8, 2026
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

PR image build and manifest generation completed successfully!

📦 PR image: quay.io/trustyai/trustyai-service-python-ci:9e392991979b3bb17be54c2fe02184e2eb11cecf

🗂️ CI manifests

devFlags:
  manifests:
    - contextDir: config
      sourcePath: ''
      uri: https://api.github.com/repos/trustyai-explainability/trustyai-service-operator-ci/tarball/service-python-9e392991979b3bb17be54c2fe02184e2eb11cecf

@SudipSinha SudipSinha added enhancement New feature or request and removed bug Something isn't working labels Jun 18, 2026
Layer 1 (transport): Change GzipRequestMiddleware.DEFAULT_PATHS from
("/data/upload",) to ("*",) so gzip decompression covers all HTTP
routes including /consumer/kserve/v2. Content-type gating and
decompression bomb protection remain intact.

Layer 2 (application): Add decompress_if_gzip() for the CloudEvent
endpoint (POST /) where Knative Eventing strips the Content-Encoding
header while leaving the body gzip-compressed. Detects gzip by magic
bytes (0x1F 0x8B) and decompresses before JSON parsing, matching the
Java service's CloudEventConsumer.decompressIfGzip() fix.

Extract process_cloud_event() from the HTTP endpoint so the upload
endpoint's internal forwarding path (data_upload.py) can call it
directly without going through HTTP request parsing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@SudipSinha SudipSinha force-pushed the fix/gzip-middleware-all-paths branch from 4639c6e to 9e39299 Compare June 18, 2026 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request high-priority Critical issues that should be addressed soon ok-to-test Proceed with CI testing python Pull requests that update python code technical-debt Code that works but needs improvement (untested, deprecated patterns, etc.) tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant