Skip to content

Allow duplicate headers #660

@OleMchls

Description

@OleMchls

Hey there,

While I was working with the Server-Timing header for Phoenix, I stumbled across the fact that Plug does not allow to set the same header twice.

Given the following comment, I assume this behavior is intended.

Adds a new response header (key) if not present, otherwise replaces the previous value of that header with value.
-- https://github.com/elixir-plug/plug/blob/master/lib/plug/conn.ex#L626-L627

I think to not support this at all is problematic as the RFC states

A sender MUST NOT generate multiple header fields with the same field name in a message unless either the entire field value for that header field is defined as a comma-separated list [i.e., #(values)] or the header field is a well-known exception (as noted below).

I want to emphasize the last part of the sentence: or the header field is a well-known exception.

These exceptions are not defined anywhere, the RFC talks about Set-Cookie but there may be more. For example, I was recently working with the Server-Timing API https://w3c.github.io/server-timing/ which allows having the same header twice.

To reproduce

# some phoenix controller
def index(conn, _params) do
  conn = Plug.Conn.put_resp_header(conn, "via", "Value A")
  conn = Plug.Conn.put_resp_header(conn, "via", "Value B")
  render conn, "index.html"
end

Expected behavior

$~ curl -I http://localhost:4000/
HTTP/1.1 200 OK
server: Cowboy
date: Wed, 14 Feb 2018 09:54:22 GMT
content-length: 1932
content-type: text/html; charset=utf-8
cache-control: max-age=0, private, must-revalidate
x-request-id: 146acnn1n4p1bc2ggh4b3rejp3t6m6ce
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
via: Value A
via: Value B

Actual behavior

$~ curl -I http://localhost:4000/
HTTP/1.1 200 OK
server: Cowboy
date: Wed, 14 Feb 2018 09:54:22 GMT
content-length: 1932
content-type: text/html; charset=utf-8
cache-control: max-age=0, private, must-revalidate
x-request-id: 146acnn1n4p1bc2ggh4b3rejp3t6m6ce
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
via: Value B

I did not find any similar issue, even though I thought this may have been discussed before. If I missed it, I am deeply sorry!

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