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