Projet

Général

Profil

Télécharger (7,9 ko) Statistiques
| Branche: | Tag: | Révision:

root / mandaye / dispatcher.py @ b1f097d4

1

    
2
import copy
3
import re
4

    
5
from urlparse import urlparse
6
from importlib import import_module
7

    
8
from mandaye import config
9
from mandaye.log import logger
10
from mandaye.mappers import default
11
from mandaye.response import _500, _302
12
from mandaye.exceptions import ImproperlyConfigured
13

    
14
# TODO: add an external url mapping
15

    
16
def import_mapping(name):
17
    if not name:
18
        return dict()
19
    if not config.mappers.has_key(name):
20
        logger.error("mapper %s not found" % name)
21
        return dict()
22
    module = config.mappers[name]
23
    try:
24
        mapper = import_module(module)
25
    except ImportError, e:
26
        raise ImproperlyConfigured('Error importing mapping %s: "%s"' % (module, e))
27
    return mapper
28

    
29

    
30
class Dispatcher(object):
31
    """ The dispatcher is the main class of Mandaye
32
    It allows you to launch the right filter on the reqest and the response
33
    """
34

    
35
    def __init__(self, env, target_url, mapper_name=None):
36
        """ env: wsgi environ
37
        target_url: the full url of your destination
38
        mepper: python module with the mapper
39
        """
40
        self.target = urlparse(target_url)
41
        self.env = env
42
        self.env['target'] = self.target
43
        self.mapper_name = mapper_name
44
        self.mapper = import_mapping(mapper_name)
45
        auth_type = self.env['mandaye.config']['auth_type']
46
        path = config.authentifications[auth_type]
47
        i = path.rfind('.')
48
        module, attr = path[:i], path[i+1:]
49
        module = import_module(module)
50
        Auth = getattr(module, attr)
51
        self.auth = Auth(env, self.mapper)
52
        mapping = []
53
        mapping.extend(self.auth.get_default_mapping())
54
        mapping.extend(default.mapping)
55
        mapping.extend(self.mapper.mapping)
56
        logger.debug('Dispatcher mapping : %r', mapping)
57
        self.req_mapping = self._parse_mapping(mapping)
58

    
59
    def __get_mappings_hooks(self, mapper, req_mapping):
60
        """ fill the request mapping with the right hooks
61
        return req_mapping
62
        """
63
        if not mapper.has_key('method') or \
64
                mapper['method'] == self.env['REQUEST_METHOD']:
65
            for hookname in req_mapping:
66
                if mapper.has_key(hookname):
67
                    if isinstance(req_mapping[hookname], list):
68
                        for entry in mapper[hookname]:
69
                            if entry.has_key('auth'):
70
                                entry['filter'] = getattr(self.auth, entry['auth'])
71
                            req_mapping[hookname].append(entry)
72
                    else:
73
                        if isinstance(mapper[hookname], dict) and \
74
                                mapper[hookname].has_key('auth'):
75
                            mapper[hookname]['filter'] = getattr(self.auth, mapper[hookname]['auth'])
76
                        req_mapping[hookname] = mapper[hookname]
77
        return req_mapping
78

    
79

    
80
    def _parse_mapping(self, mapping):
81
        """ parse the mapping on every request
82
        """
83
        req_mapping = {
84
                'on_request': [],
85
                'on_response': [],
86
                'response': None,
87
                'target': None,
88
                'redirect': None,
89
                'decompress': config.auto_decompress
90
                }
91

    
92
        if not mapping:
93
            return req_mapping
94
        for entry in mapping:
95
            if entry.has_key('path'):
96
                if isinstance(entry['path'], str):
97
                    if re.match(entry['path'], self.env['PATH_INFO']):
98
                        req_mapping = self.__get_mappings_hooks(entry, req_mapping)
99
                else:
100
                    for path in entry['path']:
101
                        if re.match(path, self.env['PATH_INFO']):
102
                            req_mapping = self.__get_mappings_hooks(entry, req_mapping)
103
            else:
104
                logger.warning('Config error: you need to specify paths in your mapping')
105
        return req_mapping
106

    
107
    def _call_hook(self, hook, *args):
108
        if hook and hook.has_key('filter'):
109
            values = hook.get('values')
110
            if not values:
111
                values = dict()
112
            return hook['filter'](self.env, values, *args)
113
        else:
114
            logger.warning("%s hook failed (no filter option)" % self.env['PATH_INFO'])
115
        return None
116

    
117
    def _is_cond_respected(self, hook, request, response):
118
        if hook.has_key('condition') and \
119
                not hook['condition'](self.env, request, response):
120
            return False
121
        return True
122

    
123
    def set_request_target(self, request):
124
        """ Add target url on not into the request
125
        """
126
        request.target = self.target.geturl() + self.env['RAW_URI']
127
        if self.req_mapping['target']:
128
            if "//" in self.req_mapping['target']:
129
                request.target = self.req_mapping['target']
130
            else:
131
                request.target = self.target.geturl() + self.req_mapping['target']
132
        elif self.req_mapping['response'] and \
133
                self._is_cond_respected(self.req_mapping['response'],
134
                        request, None):
135
            request.target = None
136
        elif self.req_mapping['redirect']:
137
            request.target = None
138
        return request
139

    
140
    def get_response(self, request):
141
        """ Called if you have a response hook for this request
142
        """
143
        if self.req_mapping['redirect']:
144
            return _302(self.req_mapping['redirect'])
145
        elif self.req_mapping['response']:
146
            logger.debug("Loading response hook(s)")
147
            hook = self.req_mapping['response']
148
            print hook
149
            response = self._call_hook(hook, request, None)
150
            if not response:
151
                return _500(self.env["PATH_INFO"], "The response hook failed")
152
        else:
153
            return _500(self.env["PATH_INFO"], "no response and no target")
154
        return response
155

    
156
    def mod_request(self, request):
157
        """ Modify the request
158
        request: MandayeRequest object with cookies and headers
159
        Return the request object """
160
        # Calling hook function
161
        for hook in self.req_mapping['on_request']:
162
            if not self._is_cond_respected(hook, request, None):
163
                continue
164
            new_request = self._call_hook(hook, request)
165
            if new_request:
166
                request = new_request
167
            else:
168
                logger.warning("%s On_request hook %s failed (empty request)" % \
169
                        (self.env['PATH_INFO'], hook['filter']))
170
        return request
171

    
172
    def mod_response(self, request, response):
173
        """ Modify the response. This will load on_response filters.
174
        request: the Mandaye request
175
        response: MandayeResponse object with cookies, headers and HTML
176
        you can modify the cookies and the HTTP headers """
177

    
178
        content_type = response.headers.getheader('content-type')
179
        if content_type:
180
            content_type = content_type.split(';')[0]
181

    
182
        # Calling hook function
183
        for hook in self.req_mapping['on_response']:
184
            if not self._is_cond_respected(hook, request, response):
185
                continue
186
            if hook.has_key('content-types') and content_type:
187
                if content_type not in hook['content-types']:
188
                    logger.debug("Don't load filter %s (content-type %s doesn't match)" % (hook['filter'], content_type))
189
                    continue
190

    
191
            if self.req_mapping['decompress']:
192
                response.decompress()
193

    
194
            try:
195
                new_response = self._call_hook(hook, request, response)
196
            except  Exception, e:
197
                new_response = _500(self.env['PATH_INFO'],
198
                        "Hook %s failed with error %s" % (hook, e),
199
                        exception=e,
200
                        env=self.env)
201
            if new_response:
202
                response = new_response
203
            else:
204
                logger.warning("%s On_response hook %s failed (empty answer)",
205
                        self.env['PATH_INFO'], hook['filter'])
206
        return response
207

    
(4-4/14)