summaryrefslogtreecommitdiff
path: root/paste/wareweb/dispatch.py
blob: 3e5f78b9525aac9c30ba8d797e3913caa2709ebc (plain)
1
2
3
4
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
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
from paste import httpexceptions
import event

__all__ = ['public', 'ActionDispatch', 'PathDispatch']

def public(func):
    func.public = True
    return func

class MethodDispatch(object):

    prefix = None

    def __addtoclass__(self, attr, cls):
        cls.listeners.append(self.respond_event)
    
    def respond_event(self, name, servlet, *args, **kw):
        if name == 'end_awake':
            return self.find_method(servlet, *args, **kw)
        return event.Continue

    def get_method(self, servlet, action):
        try:
            return action, getattr(servlet, action)
        except AttributeError:
            pass
        if self.prefix:
            try:
                return (self.prefix + action,
                        getattr(servlet, self.prefix + action))
            except AttributeError:
                pass
        return None, None

    def valid_method(self, name, method):
        if getattr(method, 'public', False):
            return True
        if self.prefix and name.startswith(self.prefix):
            return True
        return False
    
class ActionDispatch(MethodDispatch):

    prefix = 'action_'

    def __init__(self, action_name='_action_'):
        self.action_name = action_name

    def find_method(self, servlet, ret_value):
        possible_actions = []
        for name, value in servlet.fields.items():
            if name == self.action_name:
                possible_actions.append(value)
            elif name.startswith(self.action_name):
                possible_actions.append(name[len(self.action_name):])
        if not possible_actions:
            return event.Continue
        if len(possible_actions) > 1:
            raise httpexceptions.HTTPBadRequest(
                "More than one action received: %s"
                % ', '.join(map(repr, possible_actions)))
        action = possible_actions[0]
        name, method = self.get_method(servlet, action)
        if name is None:
            raise httpexceptions.Forbidden(
                "Action method not found: %r" % action)
        if not self.valid_method(name, method):
            raise httpexceptions.Forbidden(
                "Method not allowed: %r" % action)
        return method()

class PathDispatch(MethodDispatch):

    prefix = 'path_'

    def find_method(self, servlet, ret_value):
        parts = servlet.path_parts
        if not parts:
            action = 'index'
        else:
            action = parts[0]
            servlet.path_parts = parts[1:]
        name, method = self.get_method(servlet, action)
        if name is None:
            raise httpexceptions.Forbidden(
                "Method not found: %r" % action)
        if not self.valid_method(name, method):
            raise httpexceptions.Forbidden(
                "Method not allowed: %r" % action)
        return method()