# File lib/rack/ssl.rb, line 8 def self.default_hsts_options { :expires => YEAR, :subdomains => false } end
# File lib/rack/ssl.rb, line 12 def initialize(app, options = {}) @app = app @hsts = options[:hsts] @hsts = {} if @hsts.nil? || @hsts == true @hsts = self.class.default_hsts_options.merge(@hsts) if @hsts @exclude = options[:exclude] @host = options[:host] end
# File lib/rack/ssl.rb, line 23 def call(env) if @exclude && @exclude.call(env) @app.call(env) elsif scheme(env) == 'https' status, headers, body = @app.call(env) headers = hsts_headers.merge(headers) flag_cookies_as_secure!(headers) [status, headers, body] else redirect_to_https(env) end end
tools.ietf.org/html/draft-hodges-strict-transport-sec-02
# File lib/rack/ssl.rb, line 63 def hsts_headers if @hsts value = "max-age=#{@hsts[:expires]}" value += "; includeSubDomains" if @hsts[:subdomains] { 'Strict-Transport-Security' => value } else {} end end
# File lib/rack/ssl.rb, line 48 def redirect_to_https(env) req = Request.new(env) url = URI(req.url) url.scheme = "https" url.host = @host if @host status = %w[GET HEAD].include?(req.request_method) ? 301 : 307 headers = hsts_headers.merge('Content-Type' => 'text/html', 'Location' => url.to_s) [status, headers, []] rescue URI::InvalidURIError [400, {"Content-Type" => "text/plain"}, []] end
Fixed in rack >= 1.3
# File lib/rack/ssl.rb, line 38 def scheme(env) if env['HTTPS'] == 'on' 'https' elsif env['HTTP_X_FORWARDED_PROTO'] env['HTTP_X_FORWARDED_PROTO'].split(',')[0] else env['rack.url_scheme'] end end