Projet

Général

Profil

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

root / mandaye / server.py @ d02c86c7

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.exceptions import ImproperlyConfigured
15
from mandaye.dispatcher import Dispatcher
16
from mandaye.log import logger, UuidFilter
17
from mandaye.handlers.default import MandayeRedirectHandler, MandayeErrorHandler
18
from mandaye.http import HTTPHeader, HTTPRequest, HTTPResponse
19
from mandaye.response import _404, _502, _500
20
from mandaye.db import sql_session
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
            sql_session.commit()
141
        except Exception, e:
142
            sql_session.rollback()
143
            if self.raven_client:
144
                self.raven_client.captureException()
145
            response = self.on_response(start_response, _500(env['PATH_INFO'], "Unhandled exception",
146
                exception=e, env=env))
147
        finally:
148
            sql_session.close()
149
        return response
150

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

    
160

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

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

    
185
        if self.env['REQUEST_METHOD'] == 'POST':
186
            msg = self.env['wsgi.input']
187
        else:
188
            msg = None
189

    
190
        request = HTTPRequest(cookies, headers, self.env['REQUEST_METHOD'], msg, None)
191
        return self.dispatcher.set_request_target(request)
192

    
193

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

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

    
(12-12/14)