Class: Rack::AllowedHosts

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/allowed_hosts.rb,
lib/rack/allowed_hosts/version.rb

Constant Summary collapse

FORBIDDEN_RESPONSE =
[403, {'Content-Type' => 'text/html'}, ['<h1>403 Forbidden</h1>']]
VERSION =
'0.0.4'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, &block) ⇒ AllowedHosts

Returns a new instance of AllowedHosts.



11
12
13
14
15
16
17
# File 'lib/rack/allowed_hosts.rb', line 11

def initialize(app, &block)
  @app = app
  @allowed_hosts = []

  # Call the block
  instance_eval(&block)
end

Instance Attribute Details

#allowed_hostsObject (readonly)

Returns the value of attribute allowed_hosts.



9
10
11
# File 'lib/rack/allowed_hosts.rb', line 9

def allowed_hosts
  @allowed_hosts
end

Instance Method Details

#allow(*hosts) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
# File 'lib/rack/allowed_hosts.rb', line 19

def allow(*hosts)
  # Also allow the for `allow ['host-a.com', 'host-b.com']` etc.
  if hosts.size == 1 && hosts[0].is_a?(Array)
    hosts = hosts[0]
  end

  hosts.each do |host|
    matcher = matcher_for(host)
    @allowed_hosts << matcher unless @allowed_hosts.include? matcher
  end
end

#call(env) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/rack/allowed_hosts.rb', line 31

def call(env)
  http_host = env['HTTP_HOST']

  unless http_host.nil?
    http_host = http_host.split(':').first
  end

  host_values = [
    http_host,
    env['SERVER_NAME']
  ].uniq

  host_values.each do |host|
    unless host_allowed?(host)
      return FORBIDDEN_RESPONSE
    end
  end

  # Fetch the result
  @app.call(env)
end

#host_allowed?(host) ⇒ Boolean

Returns:

  • (Boolean)


53
54
55
56
57
58
59
60
61
# File 'lib/rack/allowed_hosts.rb', line 53

def host_allowed?(host)
  return false if host.nil?

  @allowed_hosts.each do |pattern|
    return true if pattern.match host
  end

  false
end

#matcher_for(host) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/rack/allowed_hosts.rb', line 63

def matcher_for(host)
  host = host.gsub(/\.\Z/, '')
  parts = host.split('.')
  pattern = nil
  parts.each do |part|
    if pattern.nil?
      pattern = prepared_part(part)
    else
      pattern = /#{pattern}\.#{prepared_part(part)}/
    end
  end
  /\A#{pattern}\Z/
end

#prepared_part(part) ⇒ Object



77
78
79
80
81
82
83
# File 'lib/rack/allowed_hosts.rb', line 77

def prepared_part(part)
  if part == '*'
    /.*/
  else
    Regexp.quote(part)
  end
end