Class: Rack::Rewrite
- Inherits:
-
Object
- Object
- Rack::Rewrite
- Defined in:
- lib/rack/rewrite.rb,
lib/rack/rewrite/rule.rb
Overview
A rack middleware for defining and applying rewrite rules. In many cases you
can get away with rack-rewrite instead of writing Apache mod_rewrite rules.
Defined Under Namespace
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#initialize(app, given_options = {}) ⇒ Rewrite
constructor
A new instance of Rewrite.
Constructor Details
#initialize(app, given_options = {}) ⇒ Rewrite
Returns a new instance of Rewrite.
9 10 11 12 13 14 15 16 17 18 19 |
# File 'lib/rack/rewrite.rb', line 9 def initialize(app, = {}, &) = { klass: RuleSet, options: {} }.merge() @app = app @rule_set = [:klass].new([:options]) @logger = [:logger] || ::Logger.new($stdout) @redis = [:redis] @rule_set.instance_eval(&) if block_given? end |
Instance Method Details
#call(env) ⇒ Object
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/rack/rewrite.rb', line 21 def call(env) if (matched_rule = find_first_matching_rule(env)) rack_response = matched_rule.apply!(env) rule_key = matched_rule.from.inspect rule_details = { rule_type: matched_rule.rule_type, from: rule_key, to: matched_rule.to } = matched_rule..dup.delete(:'Cache-Control') rule_details[:options] = if .present? unless redis.nil? redis_match = JSON.parse(redis.get(rule_key) || {}) # Log referring agent for bots for further analysis # Test by uncommenting this # ua = "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.79 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" if (ua ||= env['HTTP_USER_AGENT']).present? require 'device_detector' # Ensure all header values are strings to prevent nil gsub errors in device_detector safe_headers = (env || {}).select { |k, v| k.start_with?('HTTP_') }.transform_values { |v| v.nil? ? '' : v.to_s } dd = DeviceDetector.new(ua, safe_headers) # log bots if dd.bot? bn = dd.bot_name rule_details['bots'] = redis_match['bots'] || [] rule_details['bots'] << bn unless rule_details['bots'].include?(bn) rule_details['bots'].sort! end end # Log Referring page # Test by uncommenting this # ref = "http://www.somepage.com/referring_page" if (ref ||= env['HTTP_REFERER']).present? rule_details['ref'] = redis_match['ref'] || [] rule_details['ref'] << ref unless rule_details['ref'].include?(ref) rule_details['ref'].sort! end # Log original request path and query string if (uri = env['REQUEST_URI']).present? rule_details['uri'] = redis_match['uri'] || [] rule_details['uri'] << uri unless rule_details['uri'].include?(uri) rule_details['uri'].sort! end rule_details['counter'] = redis_match.fetch('counter', 0).to_i + 1 rule_details['last_use'] = Time.current.to_s redis.set(rule_key, rule_details.to_json) end # logger&.info "[REDIRECT] #{rule_details.inspect}" # Stringify the keys in our rack response to prevent puma from choking # https://medium.com/@ssscripting/puma-typeerror-no-implicit-conversion-of-symbol-into-string-d58df06a780b rack_response[1]&.stringify_keys! if rack_response[1].respond_to?(:stringify_keys!) # Don't invoke the app if applying the rule returns a rack response return rack_response unless rack_response === true end @app.call(env) end |