Class: Rack::BodyParser

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

Overview

BodyParser implementation.

Constant Summary collapse

REQUEST_BODY =

Where to get input.

'rack.input'.freeze
RACK_ENV_KEY =

Where to store in env

'parsed_body'.freeze
RACK_REQUEST_KEY =

Where to store in Rack::Request in case of opts

'parsed_body'.freeze
ERROR_MESSAGE =

Default error handler

"[Rack::BodyParser] Failed to parse %s: %s\n".freeze
ERROR_HANDLER =
proc do |e, type|
  [400, {}, format(ERROR_MESSAGE, type, e.to_s)]
end
HANDLERS =
{ 'default' => ERROR_HANDLER }.freeze
VERSION =
'1.0.0'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, opts = {}) ⇒ BodyParser

Returns a new instance of BodyParser.



22
23
24
25
26
27
28
# File 'lib/rack/bodyparser.rb', line 22

def initialize(app, opts = {})
  @app      = app
  @parsers  = opts.delete(:parsers) || {}
  @handlers = HANDLERS.merge(opts.delete(:handlers) || {})
  @logger   = opts.delete(:logger)
  @opts     = opts
end

Instance Attribute Details

#handlersObject (readonly)

Returns the value of attribute handlers.



20
21
22
# File 'lib/rack/bodyparser.rb', line 20

def handlers
  @handlers
end

#loggerObject (readonly)

Returns the value of attribute logger.



20
21
22
# File 'lib/rack/bodyparser.rb', line 20

def logger
  @logger
end

#parsersObject (readonly)

Returns the value of attribute parsers.



20
21
22
# File 'lib/rack/bodyparser.rb', line 20

def parsers
  @parsers
end

Instance Method Details

#call(env) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/rack/bodyparser.rb', line 30

def call(env)
  type   = Rack::Request.new(env).media_type
  parser = type && detect(parsers, type)

  if parser
    begin
      parse_with(parser.last, env) # parser.last is actual parser
    rescue StandardError => e
      return handle_error(e, type) # return error response
    end
  end

  # return control to app
  @app.call env
end

#detect(hash, what) ⇒ Object

returns [type, parser]



80
81
82
83
84
# File 'lib/rack/bodyparser.rb', line 80

def detect(hash, what)
  hash.detect do |match, _|
    match.is_a?(Regexp) ? what.match(match) : what.eql?(match)
  end
end

#handle_error(e, type) ⇒ Object



68
69
70
71
72
# File 'lib/rack/bodyparser.rb', line 68

def handle_error(e, type)
  warn!(e, type)
  handler = (detect(handlers, type) || detect(handlers, 'default')).last
  handler.call(e, type)
end

#parse_with(parser, env) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/rack/bodyparser.rb', line 53

def parse_with(parser, env)
  body = request_body(env)
  return unless body && !body.empty?

  # Give env to parser if it has a setter for it.
  parser.env = env if parser.respond_to? :env=

  # parse!
  parsed = parser.call(body)

  # store results in env, optionally in Rack::Request.
  env.update(RACK_ENV_KEY => parsed)
  patch_rack_request(parser, parsed) if @opts[:patch_request]
end

#patch_rack_request(parser, parsed) ⇒ Object



74
75
76
77
# File 'lib/rack/bodyparser.rb', line 74

def patch_rack_request(parser, parsed)
  return unless parser.respond_to?(:rack_request_key)
  Rack::Request.send(:define_method, parser.rack_request_key) { parsed }
end

#request_body(env) ⇒ Object



46
47
48
49
50
51
# File 'lib/rack/bodyparser.rb', line 46

def request_body(env)
  body = env[REQUEST_BODY].read
  env[REQUEST_BODY].rewind

  body
end

#warn!(e, type) ⇒ Object



86
87
88
89
# File 'lib/rack/bodyparser.rb', line 86

def warn!(e, type)
  return unless logger
  logger.warn format(ERROR_MESSAGE, type, e.to_s)
end