The Rack Env

Let’s have a look at the env data that is passed along with the request. Let’s just print it out to the terminal as follows:

  def call(env)
    p env
    [200, { "Content-Type" => "text/html" }, ["Yay, your first web application! <3"]]
  end

In order for the server to pick up this change we need to restart it. Go to your terminal window where rackup (WEBrick) is running our app, and hit ctrl-c. Then hit cursor-up to get the last command back (or type rackup), and hit return.

If you now refresh the page in your browser (hit cmd-r or ctrl-r depending on your operating system) you should then see … wow, quite a bit of messy output in the logs in your terminal. For me it looks like this (some less interesting bits removed):

{"GATEWAY_INTERFACE"=>"CGI/1.1", "PATH_INFO"=>"/", "QUERY_STRING"=>"", "REMOTE_ADDR"=>"127.0.0.1", "REM
OTE_HOST"=>"localhost", "REQUEST_METHOD"=>"GET", "REQUEST_URI"=>"http://localhost:9292/", "SCRIPT_NAME"
=>"", "SERVER_NAME"=>"localhost", "SERVER_PORT"=>"9292", "SERVER_PROTOCOL"=>"HTTP/1.1", "SERVER_SOFTWAR
E"=>"WEBrick/1.3.1 (Ruby/2.2.1/2015-02-26)", "HTTP_HOST"=>"localhost:9292", "HTTP_ACCEPT_LANGUAGE"=>"en
-US,en;q=0.8,de;q=0.6", "HTTP_CACHE_CONTROL"=>"max-age=0", "HTTP_ACCEPT_ENCODING"=>"gzip", "HTTP_ACCEPT
"=>"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "HTTP_USER_AGENT"=>"Mo
zilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.1
35 Safari/537.36", "rack.version"=>[1, 3], "rack.url_scheme"=>"http", "HTTP_VERSION"=>"HTTP/1.1", "REQU
EST_PATH"=>"/"}

Woha! What does all of this stuff mean?

First of all, you can see that it’s a Ruby hash with lots of keys that are all strings. Then, most of these strings are all upper case with an underscore _ as a word separator. Some of these start with HTTP_, while others don’t. However, there also are some keys that start with rack, and are all lowercase.

Rack uses a simple convention for these keys:

Let’s write a little bit of code to make this easier for us to inspect:

class Application
  def call(env)
    puts inspect_env(env)
    [200, { "Content-Type" => "text/html" }, ["Yay, your first web application! <3"]]
  end

  def inspect_env(env)
    puts format('Request headers', request_headers(env))
    puts format('Server info', server_info(env))
    puts format('Rack info', rack_info(env))
  end

  def request_headers(env)
    env.select { |key, value| key.include?('HTTP_') }
  end

  def server_info(env)
    env.reject { |key, value| key.include?('HTTP_') or key.include?('rack.') }
  end

  def rack_info(env)
    env.select { |key, value| key.include?('rack.') }
  end

  def format(heading, pairs)
    [heading, "", format_pairs(pairs), "\n"].join("\n")
  end

  def format_pairs(pairs)
    pairs.map { |key, value| '  ' + [key, value.inspect].join(': ') }
  end
end

Again, after changing your code, you’ll need to restart your server application.

For me this outputs the following (again, stripping some of the less interesting bits):

Request headers

  HTTP_HOST: "localhost:9292"
  HTTP_REFERER: "http://localhost:9292/"
  HTTP_ACCEPT_LANGUAGE: "en-US,en;q=0.8,de;q=0.6"
  HTTP_ACCEPT_ENCODING: "gzip"
  HTTP_USER_AGENT: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36"
  HTTP_ACCEPT: "*/*"
  HTTP_VERSION: "HTTP/1.1"

Server info

  GATEWAY_INTERFACE: "CGI/1.1"
  PATH_INFO: "/"
  QUERY_STRING: ""
  REMOTE_ADDR: "127.0.0.1"
  REMOTE_HOST: "localhost"
  REQUEST_METHOD: "GET"
  REQUEST_URI: "http://localhost:9292/"
  SCRIPT_NAME: ""
  SERVER_NAME: "localhost"
  SERVER_PORT: "9292"
  SERVER_PROTOCOL: "HTTP/1.1"
  SERVER_SOFTWARE: "WEBrick/1.3.1 (Ruby/2.2.1/2015-02-26)"
  REQUEST_PATH: "/"

Rack info

  rack.version: [1, 3]
  rack.url_scheme: "http"

Now, that’s way easier to read, right?

Luckily, we can just ignore most of these things.

At the moment, the only interesting keys for us are REQUEST_METHOD and PATH_INFO: They’re the relevant bits from the HTTP request.

The most interesting bits in the env hash are the REQUEST_METHOD, and PATH_INFO.

Ok, let’s do something with them.