diff --git a/CHANGELOG.md b/CHANGELOG.md index 969bb56..25964b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.0.3 (February 27, 2014) + +- Added option to specify on which hosts to perform redirection + + ## 0.0.2 (June 14, 2011) - Populate CHANGELOG. @@ -9,4 +14,4 @@ ## 0.0.1 (June 22, 2010) -- Initial release +- Initial release \ No newline at end of file diff --git a/README.md b/README.md index a0d295b..a4a483c 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,12 @@ middleware at the top of the Rack stack:: end end +You can also specify the `:only_hosts` parameter to limit redirection to specific hosts + + config.middleware.use(Rack::NoWWW, only_hosts: "www.example.org") + +Requests not made on www.example.org will not be redirected to the root domain. + Credits ------- diff --git a/lib/rack/no-www.rb b/lib/rack/no-www.rb index e1dc081..416d6c4 100644 --- a/lib/rack/no-www.rb +++ b/lib/rack/no-www.rb @@ -5,21 +5,36 @@ class NoWWW STARTS_WITH_WWW = /^www\./i - def initialize(app) + def initialize(app, options={}) + default_options = { + only_hosts: [] + } + @app = app + @options = default_options.merge(options) end def call(env) - if env['HTTP_HOST'] =~ STARTS_WITH_WWW - [301, no_www_request(env), ["Moved Permanently\n"]] + @env = env + if require_redirect? + [301, no_www_request, ["Moved Permanently\n"]] else - @app.call(env) + @app.call(@env) end end - private - def no_www_request(env) - { 'Location' => Rack::Request.new(env).url.sub(/www\./i, ''), + private + + def require_redirect? + @env['HTTP_HOST'] =~ STARTS_WITH_WWW && host_match? + end + + def host_match? + @options[:only_hosts].include?(@env['HTTP_HOST']) || @options[:only_hosts].empty? + end + + def no_www_request + { 'Location' => Rack::Request.new(@env).url.sub(/www\./i, ''), 'Content-Type' => 'text/html' } end diff --git a/lib/rack/no-www/version.rb b/lib/rack/no-www/version.rb index 3df9651..e10147d 100644 --- a/lib/rack/no-www/version.rb +++ b/lib/rack/no-www/version.rb @@ -1,5 +1,5 @@ module Rack class NoWWW - VERSION = "0.0.2" + VERSION = "0.0.3" end end diff --git a/spec/rack_no_www_spec.rb b/spec/rack_no_www_spec.rb index 56109af..2672928 100644 --- a/spec/rack_no_www_spec.rb +++ b/spec/rack_no_www_spec.rb @@ -3,37 +3,75 @@ describe "Rack::NoWWW" do include Rack::Test::Methods - - def app - mock_endpoint = lambda { |env| [200, {}, ['Hello, world.']] } - app = Rack::NoWWW.new(mock_endpoint) - end + let(:mock_endpoint) { lambda { |env| [200, {}, ["Hello, world."]] } } describe "when receiving a request with a 'www'" do + context "without the :only_hosts parameter specified" do + + let :app do + Rack::NoWWW.new(mock_endpoint) + end - before(:each) do - request '/', {'HTTP_HOST' => 'www.example.org' } - end + before(:each) do + request '/', {'HTTP_HOST' => 'www.example.org' } + end - it "should issue a 301 redirect" do - last_response.status.should == 301 - end + it "should issue a 301 redirect" do + last_response.status.should == 301 + end - it "should redirect to the URL without the 'www'" do - last_response.headers['Location'].should == "http://example.org/" + it "should redirect to the URL without the 'www'" do + last_response.headers['Location'].should == "http://example.org/" + end + + it "should have a text/html content type" do + last_response.headers['Content-Type'].should == "text/html" + end + + it "should have a body of 'Moved Permanently\\n'" do + last_response.body.should == "Moved Permanently\n" + end + end - it "should have a text/html content type" do - last_response.headers['Content-Type'].should == "text/html" + context "with a non-matching domain in the :only_hosts parameter" do + let :app do + Rack::NoWWW.new(mock_endpoint, only_hosts: ['www.do-not-redirect.org']) + end + + before(:each) do + request '/', {'HTTP_HOST' => 'www.example.org' } + end + + it "should not issue a 301 redirect" do + last_response.status.should == 200 + end end - it "should have a body of 'Moved Permanently\\n'" do - last_response.body.should == "Moved Permanently\n" + context "with a matching domain in the :only_hosts parameter" do + let :app do + Rack::NoWWW.new(mock_endpoint, only_hosts: ['www.example.org']) + end + + before(:each) do + request '/', {'HTTP_HOST' => 'www.example.org' } + end + + it "should issue a 301 redirect" do + last_response.status.should == 301 + end + + it "should redirect to the URL without the 'www'" do + last_response.headers['Location'].should == "http://example.org/" + end end - end describe "when receiving a request without a 'www'" do + let :app do + Rack::NoWWW.new(mock_endpoint) + end + it "should fall through to the app" do get '/' last_response.status.should == 200