class Rack::Buckler

Constants

DEFAULT_PORT
VERSION

Public Class Methods

new(app, opts={}) click to toggle source
# File lib/rack/buckler.rb, line 7
def initialize(app, opts={})
  @app = app
  @opts = {
    port: 3030,
    x_forwarded_for: false,
    read_timeout: 0.1,
    open_timeout: 0.1
  }
  @opts.merge!(opts)
end

Public Instance Methods

call(env) click to toggle source
# File lib/rack/buckler.rb, line 22
def call(env)
  # Contact the buckler client using the port it is listening on for http requests
  url = URI.parse("http://localhost:#{@opts[:port].to_s}/buckler")
  req = Net::HTTP::Get.new(url.to_s)

  headers = Hash[*env.select {|k,v| k.start_with? 'HTTP_'}
    .collect {|k,v| [k.sub(/^HTTP_/, ''), v]}
    .collect {|k,v| [k.split('_').collect(&:capitalize).join('-'), v]}
    .sort
    .flatten]

  headers.each do |k,v|
    req.add_field(k, v)
  end

  # Overwrite the X-Forwarded-For header
  if @opts[:x_forwarded_for]
    req.delete('X-Forwarded-For')
    req.add_field('X-Forwarded-For', env["REMOTE_ADDR"])
  end

  res = nil
  begin
    # Make sure you set a timeout to protect your application latency (this is more of a safety measure).
    res = Net::HTTP.start(url.host, url.port, read_timeout: @opts[:read_timeout], open_timeout: @opts[:open_timeout]) {|http|
      http.request(req)
    }
  rescue
    # Do nothing because we want to continue serving requests even though our call to buckler fails
  end

  # If the response from buckler is 429 then the request should be dropped.
  # Here we return status code 429 to the user.
  if res && res.code.to_i == 429
    reject_request
  else
    # Otherwise proceed to process request normally.
    @app.call(env)
  end
end
reject_request() click to toggle source
# File lib/rack/buckler.rb, line 18
def reject_request
  [429, {}, ['Too Many Requests']]
end