Projet

Général

Profil

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

root / mandaye / server.py @ c62aae38

1

    
2
import Cookie
3
import json
4
import urllib2
5
import random
6
import re
7
import os
8
import time
9

    
10
from md5 import md5
11
from urlparse import urlparse
12

    
13
from mandaye import config
14
from mandaye.backends.default import storage_conn
15
from mandaye.dispatcher import Dispatcher
16
from mandaye.exceptions import ImproperlyConfigured
17
from mandaye.log import logger, UuidFilter
18
from mandaye.handlers.default import MandayeRedirectHandler, MandayeErrorHandler
19
from mandaye.http import HTTPHeader, HTTPRequest, HTTPResponse
20
from mandaye.response import _404, _502, _500
21

    
22

    
23
def get_response(env, request, url, cookiejar=None):
24
    """ request: Mandaye Request
25
    url: the target url
26
    """
27
    # Cleaning url
28
    if config.debug:
29
        opener = urllib2.build_opener(MandayeErrorHandler, MandayeRedirectHandler,
30
                urllib2.HTTPSHandler(debuglevel=1), urllib2.HTTPHandler(debuglevel=1))
31
    else:
32
        opener = urllib2.build_opener(MandayeErrorHandler, MandayeRedirectHandler)
33
    urllib2.install_opener(opener)
34
    url = re.sub('(?<!:)/+', '/', url)
35
    if not '://' in url:
36
        url = env['target'].geturl() + url
37
    if request.req_method == 'POST':
38
        req = urllib2.Request(url, request.msg, request.headers.getheaders())
39
        logger.info('Mandaye POST %s' % url)
40
        logger.debug('POST content %s' % request.msg)
41
    else:
42
        req = urllib2.Request(url, headers=request.headers.getheaders())
43
        logger.info('Mandaye GET %s' % url)
44
    # Load the cookies
45
    if request.cookies:
46
        req.add_header('cookie', request.cookies.output(attrs=[], sep=';', header=''))
47
    try:
48
        if cookiejar != None:
49
            opener.add_handler(urllib2.HTTPCookieProcessor(cookiejar))
50
        resp = opener.open(req)
51
    except Exception, e:
52
        logger.info("%s failed with error : %s" % (url, str(e)))
53
        response = _502(env['PATH_INFO'], req.get_host(), e)
54
    else:
55
        response = HTTPResponse()
56
        response.load_from_urllib(resp)
57
        if cookiejar:
58
            response.cookies = Cookie.BaseCookie()
59
            for cookie in cookiejar:
60
                if response.cookies.get(cookie.name) == cookie.value:
61
                    continue
62
                if response.cookies.has_key(cookie.name):
63
                    del response.cookies[cookie.name]
64
                response.cookies[cookie.name] = cookie.value
65
                if cookie.expires:
66
                    response.cookies[cookie.name]['expires'] = Cookie._getdate(cookie.expires-time.time())
67
                if cookie.domain.startswith('.'):
68
                    response.cookies[cookie.name]['domain'] = cookie.domain
69
                if cookie.path:
70
                    response.cookies[cookie.name]['path'] = cookie.path
71
                # TODO: add the other RFC 2109 cookie values
72
        resp.close()
73
    return response
74

    
75

    
76
class MandayeApp(object):
77

    
78
    def __init__(self):
79
        self.env = None
80
        self.dispatcher = None
81
        self.raven_client = None
82
        if config.raven_dsn:
83
            from raven import Client
84
            self.raven_client = Client(config.raven_dsn)
85

    
86
    def __call__(self, env, start_response):
87
        """ called by the WSGI server
88
        env: standard WSGI env
89
        start_response: stanard WSGI / CGI function
90
        """
91
        response = []
92
        try:
93
            self.env = env
94
            if env.has_key('HTTP_X_FORWARDED_SCHEME'):
95
                self.env['mandaye.scheme'] = env['HTTP_X_FORWARDED_SCHEME']
96
            else:
97
                self.env['mandaye.scheme'] = env['wsgi.url_scheme']
98
            self.env['mandaye.uuid'] = self._get_uuid()
99
            self.dispatcher = None
100
            local_host = env['HTTP_HOST']
101
            path_info = env['PATH_INFO']
102
            UuidFilter.uuid = self.env['mandaye.uuid']
103
            logger.info("Client %s - %s %s://%s%s" %\
104
                    (self.env['REMOTE_ADDR'], self.env['REQUEST_METHOD'],
105
                        self.env['wsgi.url_scheme'], self.env['HTTP_HOST'],
106
                        self.env['PATH_INFO']))
107
            for conf in os.listdir(config.config_root):
108
                conf_file = os.path.join(config.config_root, conf)
109
                if os.path.isfile(conf_file):
110
                    with open(conf_file, 'r') as f:
111
                        conf = json.loads(f.read())
112
                    for param in ['site_name', 'location', 'target', 'server_name', 'mapper', 'auth_type']:
113
                        if not conf.has_key(param):
114
                            error = 'you must set %s option in vhost : %s' % \
115
                                    (param, conf_file)
116
                            logger.error(error)
117
                            raise ImproperlyConfigured, error
118
                    if not config.mappers.has_key(conf['mapper']):
119
                        err = '%s: mapper %s not found' % \
120
                                (conf_file, conf['mapper'])
121
                        logger.error(err)
122
                        raise ImproperlyConfigured, err
123
                    self.env['mandaye.auth_type'] = conf['mapper']
124
                    if not config.authentifications.has_key(conf['auth_type']):
125
                        err = '%s: authentification %s not found' % \
126
                                (conf_file, conf['auth_type'])
127
                        logger.error(err)
128
                        raise ImproperlyConfigured, err
129
                    if local_host in conf['server_name'] and \
130
                            re.match(re.compile(conf['location']), path_info):
131
                        if conf.get('force_ssl'):
132
                            self.env['mandaye.scheme'] = 'https'
133
                        self.env['mandaye.config'] = conf
134
                        self.env['mandaye.vhost'] = conf_file
135
                        self.dispatcher = Dispatcher(self.env, conf['target'],
136
                                conf['mapper'])
137
                        response = self.on_request(start_response)
138
            if not response:
139
                response = self.on_response(start_response, _404(env['PATH_INFO']))
140
            if config.storage_backend == 'mandaye.backends.sql':
141
                storage_conn.commit()
142
        except Exception, e:
143
            if config.storage_backend == 'mandaye.backends.sql':
144
                storage_conn.rollback()
145
            if self.raven_client:
146
                self.raven_client.captureException()
147
            response = self.on_response(start_response, _500(env['PATH_INFO'], "Unhandled exception",
148
                exception=e, env=env))
149
        finally:
150
            if config.storage_backend == 'mandaye.backends.sql':
151
                storage_conn.close()
152
        return response
153

    
154
    def _get_uuid(self):
155
        id_str = "%f%s%f%s" % (
156
                    time.time(),
157
                    id({}),
158
                    random.random(),
159
                    os.getpid
160
                )
161
        return md5(md5(id_str).hexdigest()).hexdigest()
162

    
163

    
164
    def _get_request(self):
165
        """ Return a Mandaye HTTP Request
166
        """
167
        headers = HTTPHeader()
168
        if self.env.get('CONTENT_LENGTH'):
169
            headers.addheader('Content-Length', self.env['CONTENT_LENGTH'])
170
        if self.env.get('CONTENT_TYPE'):
171
            headers.addheader('Content-Type', self.env['CONTENT_TYPE'])
172
        for name in (name for name in self.env if name.startswith('HTTP_')):
173
            value = self.env[name]
174
            if name != "HTTP_HOST" and name != "HTTP_COOKIE":
175
                name = name.split('HTTP_')[1].replace('_', '-')
176
                headers.addheader(name, value)
177

    
178
        cookies = Cookie.BaseCookie()
179
        if self.env.has_key('HTTP_COOKIE'):
180
            env_cookies = self.env['HTTP_COOKIE'].split(';')
181
            for env_cookie in env_cookies:
182
                if env_cookie:
183
                    try:
184
                        cookies.load(env_cookie)
185
                    except Cookie.CookieError:
186
                        logger.warning("can't parse cookie: %r", env_cookie)
187

    
188
        if self.env['REQUEST_METHOD'] == 'POST':
189
            msg = self.env['wsgi.input']
190
        else:
191
            msg = None
192

    
193
        request = HTTPRequest(cookies, headers, self.env['REQUEST_METHOD'], msg, None)
194
        return self.dispatcher.set_request_target(request)
195

    
196

    
197
    def on_request(self, start_response):
198
        request = self._get_request()
199
        # Calling the dispatcher hook for the request
200
        request = self.dispatcher.mod_request(request)
201
        if not request:
202
            return self.on_response(start_response,
203
                    _500(self.env["PATH_INFO"], "Empty request"))
204
        if not request.target:
205
            response = self.dispatcher.get_response(request)
206
        elif not "://" in request.target:
207
            url = urlparse(request.target)
208
            self.env['PATH_INFO'] = url.path
209
            self.env['RAW_URI'] = url.path
210
            self.env['QUERY_STRING'] = url.query
211
            if self.env['QUERY_STRING']:
212
                self.env['RAW_URI'] += url.query
213
            self.env['REQUEST_METHOD'] = request.req_method
214
            self.env['wsgi.input'] = request.msg
215
            self.dispatcher = Dispatcher(self.env, self.env['target'].geturl(),
216
                    self.dispatcher.mapper_name)
217
            response = self.dispatcher.get_response(request)
218
        else:
219
            response = get_response(self.env, request, request.target)
220
        if response.code != 304:
221
            response = self.dispatcher.mod_response(request, response)
222
        return self.on_response(start_response, response)
223

    
224
    def on_response(self, start_response, response):
225
        """ start_response: wsgi start_response
226
        response: an instance of HTTPResponse """
227
        response.headers.addsetcookies(response.cookies)
228
        start_response('%d %s' % (response.code, response.reason),
229
                response.headers.items())
230
        return [response.msg]
231

    
(11-11/13)