Class: PrestoHTTP::Response

Inherits:
Object
  • Object
show all
Includes:
PrestoCore::Utils
Defined in:
lib/presto/http/response/auth.rb,
lib/presto/http/response/action.rb,
lib/presto/http/response/params.rb,
lib/presto/http/response/response.rb

Constant Summary

Constant Summary

Constants included from PrestoCore::Utils

PrestoCore::Utils::PATH_MODIFIERS, PrestoCore::Utils::STATUS__NOT_FOUND, PrestoCore::Utils::STATUS__OK, PrestoCore::Utils::STATUS__PERMANENT_REDIRECT, PrestoCore::Utils::STATUS__REDIRECT, PrestoCore::Utils::STATUS__RESTRICTED, PrestoCore::Utils::STATUS__SERVER_ERROR

Instance Method Summary (collapse)

Methods included from PrestoCore::Utils

build_path, #extract_controllers, is_controller?, normalize_path, rootify_url

Constructor Details

- (Response) initialize(controller, route, app_instance = nil)

A new instance of Response



6
7
8
9
# File 'lib/presto/http/response/response.rb', line 6

def initialize controller, route, app_instance = nil
  @controller, @route = controller, route
  @app_instance = app_instance
end

Instance Method Details

- (Boolean) authenticated?

set status code, headers and body, honoring authorization status.

Returns:

  • (Boolean)


5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/presto/http/response/auth.rb', line 5

def authenticated?

  # simply return true if no restrictions defined.
  return true unless auth = @controller_instance.http.auth

  if auth.pass_validation?

    (headers = auth.post_validation_headers) &&
        @controller_instance.http.headers.update(headers)

    (status_code = auth.post_validation_status_code) &&
        @controller_instance.http.status(status_code)

    return true
  end

  # seems no credentials received from browser
  # or sent ones does not pass validation.
  # sending authorization request.
  @controller_instance.http.status_code auth.status_code
  @controller_instance.http.headers.update auth.headers
  @controller_instance.http.body [auth.body]

  nil
end

- (Object) call(env, &proc)



11
12
13
14
15
16
17
18
19
20
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
# File 'lib/presto/http/response/response.rb', line 11

def call env, &proc

  # if proc given, it will be executed instead of action
  @given_proc = proc
  @path_params = []

  catch :__presto_catch_response__ do

    rewrite env

    map, found = @controller.ctrl.map[@route]||{}, false
    if @action = map[env['REQUEST_METHOD']] || map[:*]

      @action_params = params_extracted
      @params_min, @params_max = params_required
      @path_params = params_given env['PATH_INFO'].to_s

      found = params_valid?
    else
      @action = map.values.first
    end

    @controller_instance = @controller.new(@action, env)

    if found
      sweep_sessions # should always precede auth

      if authenticated?

        @controller_instance.http.content_type content_type
        body = yield_action.to_s

        if encoding = encoding()
          body = body.force_encoding encoding
          @controller_instance.http.content_type '%s; charset=%s' % [
              @controller_instance.http.content_type,
              encoding]
        end

        @controller_instance.http.body [body]

      end

    else

      error = ::Presto.setup.error.not_found(@route, @controller, @action, *@path_params)
      @controller_instance.http.error STATUS__NOT_FOUND, error

    end
    @controller_instance.http.finish
  end
end

- (String) exec_action

executing action mapped to current path

Returns:

  • (String)


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/presto/http/response/action.rb', line 69

def exec_action

  api = nil
  if sandbox_capabilities = @controller_instance.http.sandbox_capabilities
    api = @controller_instance.http
    # replace HTTP API with a confined version
    @controller_instance.http @controller_instance.http.sandbox(*sandbox_capabilities)
  end

  result = @controller_instance.send(@action, *@path_params)

  # restoring HTTP API
  @controller_instance.http(api) if api

  result
end

- (Array) params_extracted

Returns:

  • (Array)


75
76
77
# File 'lib/presto/http/response/params.rb', line 75

def params_extracted
  @controller.instance_method(@action).parameters
end

- (Array) params_given(path)

extracting params from given path

Returns:

  • (Array)


16
17
18
# File 'lib/presto/http/response/params.rb', line 16

def params_given path
  path.split('/').map { |s| s if s.size > 0 }.compact
end

- (Array) params_required

determines the min and max number of params accepted, based on action arity. see #params_extracted for arity.

Examples:

http.map "/"

def method arg1, arg2                  # def method arg, *args
served URLs:                           # served URLs:
- /method/some-arg/some-another-arg    # - /method/at-least-one-arg
                                       # - /method/one/or/more/args
def method arg1 = nil, arg2            #
served URLs:                           # def method arg = nil, *args
- /method/some-arg/some-another-arg    # served URLs:
                                       # - /method/
def method arg1, arg2 = nil            # - /method/any/number/of/args
served URLs:                           #
- /method/some-arg/                    # def method arg, *args, last
- /method/some-arg/some-another-arg    # served URLs:
                                       # - /method/at-least/two-args
def method *args                       # - /method/two/or/more/args
served URLs:                           #
- /method/                             # def method arg = nil, *args, last
- /method/any/number/of/args           # served URLs:
                                       # - /method/at-least/one-arg
def method *args, arg                  # - /method/one/or/more/args
served URLs:                           #
- /method/at-least-one-arg
- /method/one/or/more/args

Returns:

  • (Array)


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/presto/http/response/params.rb', line 50

def params_required

  min, max = 0, @action_params.size

  unlimited = false
  @action_params.each_with_index do |setup, i|

    increment = setup[0] == :req ? true : false

    if param = @action_params.values_at(i+1)[0]
      increment = true if param[0] == :req
    end

    if setup[0] == :rest
      increment = false
      unlimited = true
    end

    min += 1 if increment
  end
  max = nil if unlimited
  [min, max]
end

- (true, false) params_valid?

checking that path params corresponds to action arity.

Returns:

  • (true, false)


7
8
9
10
11
# File 'lib/presto/http/response/params.rb', line 7

def params_valid?
  min_valid = @path_params.size >= @params_min
  max_valid = @params_max ? (@path_params.size <= @params_max) : true
  min_valid && max_valid
end

- (String) yield_action

wraps action execution into catch procs, so it would be easy to halt response by http.halt. also this method handles raised exceptions.

Returns:

  • (String)


9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/presto/http/response/action.rb', line 9

def yield_action
  begin
    hooks_a, hooks_z = hooks
    # Important! hooks ever executed, regardless cache.
    hooks_a.each { |hook| @controller_instance.instance_exec(*@path_params, &hook) }

    body = @given_proc ?
        @controller_instance.instance_exec(*@path_params, &@given_proc) :
        yield_action_body

    hooks_z.each { |hook| @controller_instance.instance_exec(*@path_params, &hook) }

    body
  rescue => e
    @controller_instance.http.error STATUS__SERVER_ERROR, ::Presto.setup.error.fatal_error(e)
  end
end

- (String) yield_action_body

execute action honoring cache strategy.

Returns:

  • (String)


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
# File 'lib/presto/http/response/action.rb', line 30

def yield_action_body

  proc = @controller.http.cache(@action)
  return exec_action unless proc &&
      instruction = @controller_instance.instance_exec(*@path_params, &proc)

  # building cache key from route and arguments.
  # each action may have multiple cached versions.
  # consider:
  #    http.cache(:content) { true }
  #    def content page, layout = 'default'
  #    end
  # now, any of links above will have own cache:
  #    /content/
  #    /content/1
  #    /content/1/summary
  cache_uniq = [@controller_instance.http.action_route, *@path_params].join('/')
  cache_pool = @controller.http.cache_pool
  cache = cache_pool.get(@controller) { Hash.new }

  case instruction
    when :truncate, :purge
      # got instruction to purge cache for current controller
      cache = Hash.new
    when :update
      # got instruction to purge cache for current action
      cache.delete cache_uniq
  end

  unless response = cache[cache_uniq]
    cache[cache_uniq] = (response = exec_action)
    cache_pool[@controller] = cache
  end
  response
end