Skip to content

Proxy success streams forward hop-by-hop response headers #6575

Description

@odysseus0

Intent to contribute

I would like to contribute a small follow-up to #6256 / #6499 for successful streamed proxy responses. The existing issue and PR correctly address the error-response path; this report covers the separate success-stream branch in handleResponse.

Live reproduction

We encountered this while qualifying self-hosted Nango 0.70.7 (nangohq/nango-server@sha256:041a8e747266d0d6b6132ad022dfc377e5bf8c7a5b783f055bc70fe5f988ea49) as a credential broker for Runner:

  1. Deploy the pinned Nango server directly as a Cloud Run ingress container.
  2. Connect a real Google Calendar account through Nango OAuth.
  3. Call GET /proxy/calendar/v3/calendars/primary/events?maxResults=1.

The same image, database, credentials, connection, and provider request returned Google's real 200 when reached directly, but Cloud Run returned an ingress-level 502 with reset reason: protocol error for every public Proxy call. Compression, decompression, and Accept-Encoding: identity variants did not change the result.

Putting Nginx in front of the same Nango container made the 200 path pass, showing that terminating and regenerating the HTTP hop removed the incompatibility. The same run independently reproduced #6256 on a Google 404; Nginx logged:

upstream sent "Content-Length" and "Transfer-Encoding" headers at the same time while reading response header from upstream

A bounded localhost response normalizer that removed framing and hop-by-hop headers then preserved provider 200, 404, 409, and 204 responses through the public Cloud Run ingress.

Success-path cause

For chunked or attachment responses, handleResponse currently copies every provider response header into res.writeHead(...). This forwards transport metadata from the provider-to-Nango hop, including Transfer-Encoding, Connection, and headers named by Connection. It also calls writeHead after starting the pipe.

Even when the copied framing happens to be accepted, these fields describe the previous HTTP connection and should be regenerated for the Nango-to-client hop.

Proposed change

  • Strip hop-by-hop headers and headers named by Connection from streamed success responses.
  • Strip Content-Length when the provider response was chunked or Axios decompressed the body.
  • Preserve Content-Length for an uncompressed attachment with a known length.
  • Write the sanitized status and headers before piping the body directly to the response.
  • Add a regression test covering conflicting framing, standard hop-by-hop headers, a Connection-nominated header, and write-before-pipe ordering.

I have a focused implementation ready and will open it as a draft PR referencing this issue unless maintainers prefer that #6499 absorb the success-path change.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions