Skip to content

Bug: Response headers are malformed on every response #5

@Piyush-Goenka

Description

@Piyush-Goenka

Summary

ResponseBuilder iterates response headers with each_slice(2) over an already-paired array. This collapses each header's name and value into a single stringified Ruby array, so every response leaves the server with malformed headers — including a missing/invalid Content-Type.

  • File: lib/responses/response_builder.rb
  • Severity: High (affects 100% of responses)
  • Type: Correctness bug

What happens

Even with the single Content-Type header that ResponseFactory produces today, the server writes this to the socket:

["content-type", "text/html"]: 

The header name becomes the stringified array ["content-type", "text/html"] and the value is empty, so no valid Content-Type is ever sent. With two or more headers, adjacent pairs get merged together and mangled completely.

As a side effect, the exclusion guard is also dead:

next if %w[content-length connection].include?(key.to_s.downcase)

key is now an Array, so key.to_s.downcase never matches and the filter never runs.

Why it slipped through

Browsers MIME-sniff the response body, so the demo (cave.jpg) still renders and looks correct. Any client that trusts Content-Type — API consumers, fetch() reading response.headers, content negotiation — gets the wrong result. Existing specs pass only because Net::HTTP tolerates the malformed output and there is just one header.

Steps to reproduce

  1. Start the server and request any file (e.g. GET /cave.jpg).
  2. Inspect the raw response headers (curl -i or read the socket directly).
  3. Observe there is no valid Content-Type header; instead a malformed line like ["content-type", "image/jpeg"]: is present.

Fix

- response.headers.fields.each_slice(2) do |key, value|
+ response.headers.fields.each do |key, value|

This restores correct header lines and revives the content-length/connection exclusion filter.

Follow-up

Add a spec that reads the raw socket bytes and asserts a literal Content-Type: text/html\r\n line, so the regression is locked out (current
tests pass only because Net::HTTP tolerates the malformed output).

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