2011-09-13 19:13:14 +02:00
|
|
|
|
2011-08-24 19:23:26 +02:00
|
|
|
import Cookie
|
2014-05-21 13:15:40 +02:00
|
|
|
import json
|
2011-08-03 19:24:26 +02:00
|
|
|
import urllib2
|
2011-12-23 11:01:03 +01:00
|
|
|
import random
|
2011-08-03 19:24:26 +02:00
|
|
|
import re
|
2011-12-23 11:01:03 +01:00
|
|
|
import os
|
2011-10-17 15:52:02 +02:00
|
|
|
import time
|
2011-09-13 19:13:14 +02:00
|
|
|
|
2011-12-23 11:01:03 +01:00
|
|
|
from md5 import md5
|
2013-06-04 19:20:10 +02:00
|
|
|
from urlparse import urlparse
|
2011-12-23 11:01:03 +01:00
|
|
|
|
2013-05-22 18:46:50 +02:00
|
|
|
from mandaye import config
|
2014-09-10 18:51:54 +02:00
|
|
|
from mandaye.backends.default import storage_conn
|
2011-09-13 19:13:14 +02:00
|
|
|
from mandaye.dispatcher import Dispatcher
|
2014-09-10 18:51:54 +02:00
|
|
|
from mandaye.exceptions import ImproperlyConfigured
|
2014-05-27 18:38:44 +02:00
|
|
|
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
|
2011-09-16 19:13:17 +02:00
|
|
|
from mandaye.response import _404, _502, _500
|
2011-08-10 18:15:26 +02:00
|
|
|
|
2013-12-03 17:19:43 +01:00
|
|
|
|
2011-09-21 19:34:02 +02:00
|
|
|
def get_response(env, request, url, cookiejar=None):
|
2011-09-19 19:18:32 +02:00
|
|
|
""" request: Mandaye Request
|
|
|
|
url: the target url
|
|
|
|
"""
|
2013-05-30 19:04:09 +02:00
|
|
|
# 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)
|
2011-09-23 10:41:24 +02:00
|
|
|
url = re.sub('(?<!:)/+', '/', url)
|
2013-05-30 19:04:09 +02:00
|
|
|
if not '://' in url:
|
|
|
|
url = env['target'].geturl() + url
|
2011-09-19 19:18:32 +02:00
|
|
|
if request.req_method == 'POST':
|
|
|
|
req = urllib2.Request(url, request.msg, request.headers.getheaders())
|
2011-12-23 11:01:03 +01:00
|
|
|
logger.info('Mandaye POST %s' % url)
|
|
|
|
logger.debug('POST content %s' % request.msg)
|
2011-09-19 19:18:32 +02:00
|
|
|
else:
|
|
|
|
req = urllib2.Request(url, headers=request.headers.getheaders())
|
2011-12-23 11:01:03 +01:00
|
|
|
logger.info('Mandaye GET %s' % url)
|
2011-09-19 19:18:32 +02:00
|
|
|
# Load the cookies
|
2011-09-21 19:34:02 +02:00
|
|
|
if request.cookies:
|
|
|
|
req.add_header('cookie', request.cookies.output(attrs=[], sep=';', header=''))
|
2011-09-19 19:18:32 +02:00
|
|
|
try:
|
2011-09-21 19:34:02 +02:00
|
|
|
if cookiejar != None:
|
|
|
|
opener.add_handler(urllib2.HTTPCookieProcessor(cookiejar))
|
2011-09-19 19:18:32 +02:00
|
|
|
resp = opener.open(req)
|
|
|
|
except Exception, e:
|
2013-06-04 19:20:10 +02:00
|
|
|
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)
|
2011-09-19 19:18:32 +02:00
|
|
|
else:
|
|
|
|
response = HTTPResponse()
|
|
|
|
response.load_from_urllib(resp)
|
2011-09-21 19:34:02 +02:00
|
|
|
if cookiejar:
|
2011-09-29 15:39:03 +02:00
|
|
|
response.cookies = Cookie.BaseCookie()
|
2011-09-21 19:34:02 +02:00
|
|
|
for cookie in cookiejar:
|
2011-10-17 15:52:02 +02:00
|
|
|
if response.cookies.get(cookie.name) == cookie.value:
|
|
|
|
continue
|
2011-09-22 12:31:46 +02:00
|
|
|
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:
|
2011-10-17 15:52:02 +02:00
|
|
|
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
|
2011-09-22 12:31:46 +02:00
|
|
|
# TODO: add the other RFC 2109 cookie values
|
2011-09-21 19:34:02 +02:00
|
|
|
resp.close()
|
2011-09-19 19:18:32 +02:00
|
|
|
return response
|
|
|
|
|
|
|
|
|
2016-03-24 10:27:23 +01:00
|
|
|
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)):
|
2016-03-24 10:27:23 +01:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2011-09-02 19:28:49 +02:00
|
|
|
class MandayeApp(object):
|
2011-08-03 19:24:26 +02:00
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
self.env = None
|
|
|
|
self.dispatcher = None
|
2014-05-27 13:20:27 +02:00
|
|
|
self.raven_client = None
|
|
|
|
if config.raven_dsn:
|
|
|
|
from raven import Client
|
|
|
|
self.raven_client = Client(config.raven_dsn)
|
2011-08-03 19:24:26 +02:00
|
|
|
|
|
|
|
def __call__(self, env, start_response):
|
|
|
|
""" called by the WSGI server
|
|
|
|
env: standard WSGI env
|
|
|
|
start_response: stanard WSGI / CGI function
|
|
|
|
"""
|
2011-10-13 15:43:46 +02:00
|
|
|
response = []
|
2011-10-11 15:41:59 +02:00
|
|
|
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']
|
2011-12-23 11:01:03 +01:00
|
|
|
self.env['mandaye.uuid'] = self._get_uuid()
|
2011-10-11 15:41:59 +02:00
|
|
|
self.dispatcher = None
|
|
|
|
local_host = env['HTTP_HOST']
|
|
|
|
path_info = env['PATH_INFO']
|
2014-05-27 18:38:44 +02:00
|
|
|
UuidFilter.uuid = self.env['mandaye.uuid']
|
2011-12-23 11:01:03 +01:00
|
|
|
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']))
|
2014-05-21 13:15:40 +02:00
|
|
|
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
|
2016-03-24 10:27:23 +01:00
|
|
|
for param in ['location', 'target', 'server_name', 'mapper', 'auth_type']:
|
|
|
|
if param in conf:
|
|
|
|
conf[param] = strize(conf[param])
|
2014-05-21 13:15:40 +02:00
|
|
|
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'):
|
2011-10-11 15:41:59 +02:00
|
|
|
self.env['mandaye.scheme'] = 'https'
|
2014-05-21 13:15:40 +02:00
|
|
|
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)
|
2011-10-13 15:43:46 +02:00
|
|
|
if not response:
|
2014-05-21 13:15:40 +02:00
|
|
|
response = self.on_response(start_response, _404(env['PATH_INFO']))
|
2014-09-10 18:51:54 +02:00
|
|
|
if config.storage_backend == 'mandaye.backends.sql':
|
|
|
|
storage_conn.commit()
|
2011-10-11 15:41:59 +02:00
|
|
|
except Exception, e:
|
2014-09-10 18:51:54 +02:00
|
|
|
if config.storage_backend == 'mandaye.backends.sql':
|
|
|
|
storage_conn.rollback()
|
2014-05-27 13:20:27 +02:00
|
|
|
if self.raven_client:
|
|
|
|
self.raven_client.captureException()
|
2011-10-13 15:43:46 +02:00
|
|
|
response = self.on_response(start_response, _500(env['PATH_INFO'], "Unhandled exception",
|
|
|
|
exception=e, env=env))
|
2011-10-11 15:41:59 +02:00
|
|
|
finally:
|
2014-09-10 18:51:54 +02:00
|
|
|
if config.storage_backend == 'mandaye.backends.sql':
|
|
|
|
storage_conn.close()
|
2011-10-13 15:43:46 +02:00
|
|
|
return response
|
2011-12-23 11:01:03 +01:00
|
|
|
|
|
|
|
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-10-11 15:41:59 +02:00
|
|
|
|
2011-08-03 19:24:26 +02:00
|
|
|
|
2011-08-31 19:54:24 +02:00
|
|
|
def _get_request(self):
|
|
|
|
""" Return a Mandaye HTTP Request
|
|
|
|
"""
|
|
|
|
headers = HTTPHeader()
|
2011-10-10 23:10:13 +02:00
|
|
|
if self.env.get('CONTENT_LENGTH'):
|
2011-08-31 19:54:24 +02:00
|
|
|
headers.addheader('Content-Length', self.env['CONTENT_LENGTH'])
|
2011-10-10 23:10:13 +02:00
|
|
|
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)
|
|
|
|
|
2014-09-04 18:09:05 +02:00
|
|
|
cookies = Cookie.BaseCookie()
|
2014-10-08 18:02:44 +02:00
|
|
|
env_cookies = self.env.get('HTTP_COOKIE', '').split(';')
|
2014-10-01 11:41:38 +02:00
|
|
|
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
|
|
|
|
|
2014-07-09 14:30:45 +02:00
|
|
|
request = HTTPRequest(cookies, headers, self.env['REQUEST_METHOD'], msg, None)
|
|
|
|
return self.dispatcher.set_request_target(request)
|
2011-11-17 18:47:47 +01:00
|
|
|
|
2011-08-31 19:54:24 +02:00
|
|
|
|
2011-08-03 19:24:26 +02:00
|
|
|
def on_request(self, start_response):
|
2011-09-19 19:18:32 +02:00
|
|
|
request = self._get_request()
|
2011-08-31 19:54:24 +02:00
|
|
|
# Calling the dispatcher hook for the request
|
2014-12-03 16:49:23 +01:00
|
|
|
response = self.dispatcher.mod_request(request)
|
|
|
|
if response:
|
|
|
|
return response
|
2011-11-17 18:47:47 +01:00
|
|
|
if not request.target:
|
|
|
|
response = self.dispatcher.get_response(request)
|
2013-06-04 19:20:10 +02:00
|
|
|
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
|
2013-06-04 19:20:10 +02:00
|
|
|
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
|
2013-06-04 19:20:10 +02:00
|
|
|
self.env['REQUEST_METHOD'] = request.req_method
|
|
|
|
self.env['wsgi.input'] = request.msg
|
|
|
|
self.dispatcher = Dispatcher(self.env, self.env['target'].geturl(),
|
2014-05-21 13:15:40 +02:00
|
|
|
self.dispatcher.mapper_name)
|
2013-06-04 19:20:10 +02:00
|
|
|
response = self.dispatcher.get_response(request)
|
2011-11-17 18:47:47 +01:00
|
|
|
else:
|
|
|
|
response = get_response(self.env, request, request.target)
|
2013-12-03 17:19:43 +01:00
|
|
|
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)
|
2011-08-03 19:24:26 +02:00
|
|
|
|
|
|
|
def on_response(self, start_response, response):
|
2011-09-09 22:26:57 +02:00
|
|
|
""" start_response: wsgi start_response
|
|
|
|
response: an instance of HTTPResponse """
|
2011-08-31 19:54:24 +02:00
|
|
|
response.headers.addsetcookies(response.cookies)
|
2011-09-16 19:13:17 +02:00
|
|
|
start_response('%d %s' % (response.code, response.reason),
|
2011-08-31 19:54:24 +02:00
|
|
|
response.headers.items())
|
|
|
|
return [response.msg]
|
2011-08-03 19:24:26 +02:00
|
|
|
|