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"]]

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):

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

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"]]

  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))

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

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

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

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

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

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_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: "*/*"

Server info

  PATH_INFO: "/"
  REMOTE_HOST: "localhost"
  REQUEST_URI: "http://localhost:9292/"
  SERVER_NAME: "localhost"
  SERVER_PORT: "9292"
  SERVER_SOFTWARE: "WEBrick/1.3.1 (Ruby/2.2.1/2015-02-26)"

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.