Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestion: return response header values as arrays since they can have multiple values #44

Closed
myronmarston opened this issue Mar 28, 2011 · 6 comments

Comments

@myronmarston
Copy link
Contributor

For background, see issue 43.

Currently header values are strings. When the response contains multiple values for the same header, it is a comma separated string (as of the fix for issue 43).

I think it'd be nice if the header values were arrays so that multiple values are explicit. Using a comma-separated string has potential encoding issues: how does a user distinguish between a single value of a string containing a comma, and a header of multiple values?

As @mislav pointed out, changing mutli-value headers to an array could create confusion for the user if the values are strings sometimes (i.e. for singel values) and arrays other times. I'm not sure of the best idea for that, but one idea is to keep the current behavior for env[:response_headers], with a deprecation warning, and add a new hash entry (maybe env[:response_header_hash] or something) that returns a hash with arrays for all values. That would make things consistent (use all arrays), while not breaking existing users who depend on header values being strings.

@sferik
Copy link
Member

sferik commented Mar 29, 2011

I'd support a backwards-incompatible change that makes env[:response_headers] always return headers with array values. It's crazy how inconsistent (and wrong) the behavior is in some of the existing adapters.

@mislav
Copy link
Contributor

mislav commented Mar 30, 2011

Inconsistent—yes. But headers as strings are definitely more convenient to use. Imagine having to type env[:response_headers][:content_type].first or env[:response_headers][:location][0] all the time.

I'm tempted to implement something like Net::HTTP headers, where you have to use a special method to access multivalues as arrays.

Also, from the spec:

Multiple message-header fields with the same field-name MAY be present in a message if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)]. It MUST be possible to combine the multiple header fields into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field-value to the first, each separated by a comma. The order in which header fields with the same field-name are received is therefore significant to the interpretation of the combined field value, and thus a proxy MUST NOT change the order of these field values when a message is forwarded.

@myronmarston
Copy link
Contributor Author

@mislav: Interesting. Thanks for quoting the spec. I need to read the RFCs more.

I guess the encoding issue I mentioned for using a comma-separated values is a non-issue.

I'm tempted to implement something like Net::HTTP headers, where you have to use a special method to access multivalues as arrays.

That might be worthwhile.

@technoweenie
Copy link
Member

I definitely don't want every header value to be an array. I hated that shit from ASP 3.0 :)

for i=1 to Request.QueryString("n").Count
  Response.Write(Request.QueryString("n")(i)
next

@mislav
Copy link
Contributor

mislav commented Aug 12, 2012

Seems like we agreed to keep comma-separated values as String. Closing…

@mislav mislav closed this as completed Aug 12, 2012
@heisters
Copy link

heisters commented Nov 2, 2012

For what it's worth, this is an issue when multiple Set-Cookie headers are sent, since Set-Cookie contains a comma in the expires clause, eg.:

foo=bar; expires=Sat, 03-Nov-2012 16:37:48 GMT; path=/; domain=.example.com; HttpOnly

I thought I would solve this by subclassing the Faraday NetHttp adapter or inserting a middleware, but unfortunately the fact that joining by comma is baked into Utils::Headers makes all of that impossible. At the very least it would be nice if those of us that want an array of values had an easy and maintainable way of getting it.

This appears to be a known issue with the RFC and many client implementations, eg. Google AppEngine: http://code.google.com/p/googleappengine/issues/detail?id=3379

At this point, the only possible solution seems to be to manually parse the concatenated header using a regex that avoids splitting in the middle of the expires clause.

response.headers["set-cookie"].split(/, (?=[^;]+=[^;]+;)/)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants