This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
mandaye/mandaye/server.py

245 lines
10 KiB
Python
Raw Normal View History

2011-08-24 19:23:26 +02:00
import Cookie
import json
import urllib2
import random
import re
import os
import time
from md5 import md5
from urlparse import urlparse
from mandaye import config
from mandaye.backends.default import storage_conn
from mandaye.dispatcher import Dispatcher
from mandaye.exceptions import ImproperlyConfigured
from mandaye.log import logger, UuidFilter
2011-08-31 19:54:24 +02:00
from mandaye.handlers.default import MandayeRedirectHandler, MandayeErrorHandler
from mandaye.http import HTTPHeader, HTTPRequest, HTTPResponse
from mandaye.response import _404, _502, _500
2011-09-21 19:34:02 +02:00
def get_response(env, request, url, cookiejar=None):
""" request: Mandaye Request
url: the target url
"""
# Cleaning url
2014-04-15 19:35:22 +02:00
if config.debug:
opener = urllib2.build_opener(MandayeErrorHandler, MandayeRedirectHandler,
urllib2.HTTPSHandler(debuglevel=1), urllib2.HTTPHandler(debuglevel=1))
else:
opener = urllib2.build_opener(MandayeErrorHandler, MandayeRedirectHandler)
urllib2.install_opener(opener)
url = re.sub('(?<!:)/+', '/', url)
if not '://' in url:
url = env['target'].geturl() + url
if request.req_method == 'POST':
req = urllib2.Request(url, request.msg, request.headers.getheaders())
logger.info('Mandaye POST %s' % url)
logger.debug('POST content %s' % request.msg)
else:
req = urllib2.Request(url, headers=request.headers.getheaders())
logger.info('Mandaye GET %s' % url)
# Load the cookies
2011-09-21 19:34:02 +02:00
if request.cookies:
req.add_header('cookie', request.cookies.output(attrs=[], sep=';', header=''))
try:
2011-09-21 19:34:02 +02:00
if cookiejar != None:
opener.add_handler(urllib2.HTTPCookieProcessor(cookiejar))
resp = opener.open(req)
except Exception, e:
logger.info("%s failed with error : %s" % (url, str(e)))
2011-09-21 19:34:02 +02:00
response = _502(env['PATH_INFO'], req.get_host(), e)
else:
response = HTTPResponse()
response.load_from_urllib(resp)
2011-09-21 19:34:02 +02:00
if cookiejar:
response.cookies = Cookie.BaseCookie()
2011-09-21 19:34:02 +02:00
for cookie in cookiejar:
if response.cookies.get(cookie.name) == cookie.value:
continue
if response.cookies.has_key(cookie.name):
del response.cookies[cookie.name]
2011-09-21 19:34:02 +02:00
response.cookies[cookie.name] = cookie.value
if cookie.expires:
response.cookies[cookie.name]['expires'] = Cookie._getdate(cookie.expires-time.time())
if cookie.domain.startswith('.'):
2011-09-21 19:34:02 +02:00
response.cookies[cookie.name]['domain'] = cookie.domain
if cookie.path:
response.cookies[cookie.name]['path'] = cookie.path
# TODO: add the other RFC 2109 cookie values
2011-09-21 19:34:02 +02:00
resp.close()
return response
def strize(v):
'''Flatten unicode strings to str encoded as UTF-8'''
if isinstance(v, unicode):
return v.encode('utf-8')
2016-04-23 17:04:01 +02:00
if isinstance(v, (list, tuple)):
return type(v)([strize(e) for e in v])
if isinstance(v, dict):
return dict((strize(k), strize(e)) for k, e in v.iteritems())
return v
class MandayeApp(object):
def __init__(self):
self.env = None
self.dispatcher = None
self.raven_client = None
if config.raven_dsn:
from raven import Client
self.raven_client = Client(config.raven_dsn)
def __call__(self, env, start_response):
""" called by the WSGI server
env: standard WSGI env
start_response: stanard WSGI / CGI function
"""
response = []
try:
self.env = env
2011-11-10 16:43:56 +01:00
if env.has_key('HTTP_X_FORWARDED_SCHEME'):
self.env['mandaye.scheme'] = env['HTTP_X_FORWARDED_SCHEME']
else:
self.env['mandaye.scheme'] = env['wsgi.url_scheme']
self.env['mandaye.uuid'] = self._get_uuid()
self.dispatcher = None
local_host = env['HTTP_HOST']
path_info = env['PATH_INFO']
UuidFilter.uuid = self.env['mandaye.uuid']
logger.info("Client %s - %s %s://%s%s" %\
(self.env['REMOTE_ADDR'], self.env['REQUEST_METHOD'],
self.env['wsgi.url_scheme'], self.env['HTTP_HOST'],
self.env['PATH_INFO']))
for conf in os.listdir(config.config_root):
conf_file = os.path.join(config.config_root, conf)
if os.path.isfile(conf_file):
with open(conf_file, 'r') as f:
conf = json.loads(f.read())
for param in ['site_name', 'location', 'target', 'server_name', 'mapper', 'auth_type']:
if not conf.has_key(param):
error = 'you must set %s option in vhost : %s' % \
(param, conf_file)
logger.error(error)
raise ImproperlyConfigured, error
for param in ['location', 'target', 'server_name', 'mapper', 'auth_type']:
if param in conf:
conf[param] = strize(conf[param])
if not config.mappers.has_key(conf['mapper']):
err = '%s: mapper %s not found' % \
(conf_file, conf['mapper'])
logger.error(err)
raise ImproperlyConfigured, err
if not config.authentifications.has_key(conf['auth_type']):
err = '%s: authentification %s not found' % \
(conf_file, conf['auth_type'])
logger.error(err)
raise ImproperlyConfigured, err
if local_host in conf['server_name'] and \
re.match(re.compile(conf['location']), path_info):
if conf.get('force_ssl'):
self.env['mandaye.scheme'] = 'https'
self.env['mandaye.config'] = conf
self.env['mandaye.vhost'] = conf_file
self.dispatcher = Dispatcher(self.env, conf['target'],
conf['mapper'])
response = self.on_request(start_response)
if not response:
response = self.on_response(start_response, _404(env['PATH_INFO']))
if config.storage_backend == 'mandaye.backends.sql':
storage_conn.commit()
except Exception, e:
if config.storage_backend == 'mandaye.backends.sql':
storage_conn.rollback()
if self.raven_client:
self.raven_client.captureException()
response = self.on_response(start_response, _500(env['PATH_INFO'], "Unhandled exception",
exception=e, env=env))
finally:
if config.storage_backend == 'mandaye.backends.sql':
storage_conn.close()
return response
def _get_uuid(self):
id_str = "%f%s%f%s" % (
time.time(),
id({}),
random.random(),
os.getpid
)
return md5(md5(id_str).hexdigest()).hexdigest()
2011-08-31 19:54:24 +02:00
def _get_request(self):
""" Return a Mandaye HTTP Request
"""
headers = HTTPHeader()
if self.env.get('CONTENT_LENGTH'):
2011-08-31 19:54:24 +02:00
headers.addheader('Content-Length', self.env['CONTENT_LENGTH'])
if self.env.get('CONTENT_TYPE'):
2011-08-31 19:54:24 +02:00
headers.addheader('Content-Type', self.env['CONTENT_TYPE'])
for name in (name for name in self.env if name.startswith('HTTP_')):
value = self.env[name]
if name != "HTTP_HOST" and name != "HTTP_COOKIE":
name = name.split('HTTP_')[1].replace('_', '-')
headers.addheader(name, value)
cookies = Cookie.BaseCookie()
env_cookies = self.env.get('HTTP_COOKIE', '').split(';')
ok_cookies = []
for cookie in env_cookies:
try:
cookies.load(cookie)
ok_cookies.append(cookie)
except Cookie.CookieError:
logger.warning("Can't parse cookie %r", cookie)
self.env['HTTP_COOKIE'] = ';'.join(ok_cookies)
2011-08-31 19:54:24 +02:00
if self.env['REQUEST_METHOD'] == 'POST':
msg = self.env['wsgi.input']
else:
msg = None
request = HTTPRequest(cookies, headers, self.env['REQUEST_METHOD'], msg, None)
return self.dispatcher.set_request_target(request)
2011-08-31 19:54:24 +02:00
def on_request(self, start_response):
request = self._get_request()
2011-08-31 19:54:24 +02:00
# Calling the dispatcher hook for the request
response = self.dispatcher.mod_request(request)
if response:
return response
if not request.target:
response = self.dispatcher.get_response(request)
elif not "://" in request.target:
url = urlparse(request.target)
self.env['PATH_INFO'] = url.path
2014-05-28 19:58:14 +02:00
self.env['RAW_URI'] = url.path
self.env['QUERY_STRING'] = url.query
2014-05-28 19:58:14 +02:00
if self.env['QUERY_STRING']:
self.env['RAW_URI'] += url.query
self.env['REQUEST_METHOD'] = request.req_method
self.env['wsgi.input'] = request.msg
self.dispatcher = Dispatcher(self.env, self.env['target'].geturl(),
self.dispatcher.mapper_name)
response = self.dispatcher.get_response(request)
else:
response = get_response(self.env, request, request.target)
if response.code != 304:
response = self.dispatcher.mod_response(request, response)
2011-08-24 19:23:26 +02:00
return self.on_response(start_response, response)
def on_response(self, start_response, response):
""" start_response: wsgi start_response
response: an instance of HTTPResponse """
2011-08-31 19:54:24 +02:00
response.headers.addsetcookies(response.cookies)
start_response('%d %s' % (response.code, response.reason),
2011-08-31 19:54:24 +02:00
response.headers.items())
return [response.msg]