Daily Code Reading #10 – Rack::ForceDomain

Today’s coderack.org middleware is Rack::ForceDomain. This middleware forces all requests to go to a single domain. This is useful to unite the “www.example.com” and “example.com” domains so they all end up at a single domain.

The Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
require 'rack'
 
class Rack::ForceDomain
  def initialize(app, domain)
    @app = app
    @domain = domain
  end
 
  def call(env)
    request = Rack::Request.new(env)
    if @domain and request.host != @domain
      fake_request = Rack::Request.new(env.merge("HTTP_HOST" => @domain))
      Rack::Response.new([], 301, "Location" => fake_request.url).finish
    else
      @app.call(env)
    end
  end
end

Code

Review

When a request’s host doesn’t match the configured @domain Rack::ForceDomain creates a new Request and Response objects. These two objects are where the good things happen.

1
fake_request = Rack::Request.new(env.merge("HTTP_HOST" => @domain))

A new Request is created that mimics the current request but with a different HTTP_HOST. This means the scheme (http/https), port, path, and query string are copied over and the host is changed to @domain.

1
Rack::Response.new([], 301, "Location" => fake_request.url).finish

Then a Response is created as a redirection to the url that’s generated from the new Response. #finish is called on the Response to send it back to the client, which causes their browser to redirect.

I’m using some similar code in an application to redirect “example.com” to “www.example.com”, but I’m doing it all inside of Rails. If this can be done inside of Rack, I might be able to squeeze out a bit more performance from that case. If it happens enough that is…