Rack::Request - how do I get all headers?
The HTTP headers are available in the Rack environment passed to your app:
HTTP_
Variables: Variables corresponding to the client-supplied HTTP request headers (i.e., variables whose names begin with HTTP_). The presence or absence of these variables should correspond with the presence or absence of the appropriate HTTP header in the request.
So the HTTP headers are prefixed with "HTTP_" and added to the hash.
Here's a little program that extracts and displays them:
require 'rack'app = Proc.new do |env| headers = env.select {|k,v| k.start_with? 'HTTP_'} .collect {|key, val| [key.sub(/^HTTP_/, ''), val]} .collect {|key, val| "#{key}: #{val}<br>"} .sort [200, {'Content-Type' => 'text/html'}, headers]endRack::Server.start :app => app, :Port => 8080
When I run this, in addition to the HTTP headers as shown by Chrome or Firefox, there is a "VERSION: HTPP/1.1" (i.e. an entry with key "HTTP_VERSION" and value "HTTP/1.1" is being added to the env hash).
Based on @matt's answer, but this really gives you the request headers in a hash as requested in the question:
headers = Hash[*env.select {|k,v| k.start_with? 'HTTP_'} .collect {|k,v| [k.sub(/^HTTP_/, ''), v]} .collect {|k,v| [k.split('_').collect(&:capitalize).join('-'), v]} .sort .flatten]
Depending on what key convention you prefer you might want to use something else instead of :capitalize.
Like @Gavriel's answer, but using transform_keys
(simpler):
class Request def headers env.select { |k,v| k.start_with? 'HTTP_'}. transform_keys { |k| k.sub(/^HTTP_/, '').split('_').map(&:capitalize).join('-') } endend
You can even make it so lookups still work even if the case is different:
def headers env. select { |k,v| k.start_with? 'HTTP_'}. transform_keys { |k| k.sub(/^HTTP_/, '').split('_').map(&:capitalize).join('-') }. sort.to_h. tap do |headers| headers.define_singleton_method :[] do |k| super(k.split(/[-_]/).map(&:capitalize).join('-')) end end end
So for example, even if headers
normalizes the keys so it returns this:
{ Dnt: '1', Etag: 'W/"ec4454af5ae1bacff1afc5a06a2133f4"', 'X-Xss-Protection': '1; mode=block',}
you can still look up headers using the more natural/common names for these headers:
headers['DNT']headers['ETag']headers['X-XSS-Protection']