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

188 lines
6.9 KiB
Python

# gevent patching
#from gevent import monkey
#monkey.patch_all()
import Cookie
import config
import logging
import urllib
import urllib2
import re
import sys
import traceback
import poster.streaminghttp
from beaker.middleware import SessionMiddleware
from cgi import escape
from gevent.pywsgi import WSGIServer, WSGIHandler
from static import Cling
from mandaye.config import debug
from mandaye.dispatcher import Dispatcher
from mandaye.handlers.default import MandayeRedirectHandler, MandayeErrorHandler
from mandaye.http import HTTPHeader, HTTPRequest, HTTPResponse
from mandaye.response import _404, _502, _500
from mandaye.db import sql_session
# Init poster
opener = poster.streaminghttp.register_openers()
def get_response(env, request, url, cookiejar=None):
""" request: Mandaye Request
url: the target url
"""
url = re.sub('(?<!:)/+', '/', url)
if request.req_method == 'POST':
req = urllib2.Request(url, request.msg, request.headers.getheaders())
else:
req = urllib2.Request(url, headers=request.headers.getheaders())
# Load the cookies
if request.cookies:
req.add_header('cookie', request.cookies.output(attrs=[], sep=';', header=''))
try:
if debug:
opener = urllib2.build_opener(MandayeErrorHandler, MandayeRedirectHandler,
urllib2.HTTPSHandler(debuglevel=1), urllib2.HTTPHandler(debuglevel=1))
else:
opener = urllib2.build_opener(MandayeErrorHandler, MandayeRedirectHandler)
if cookiejar != None:
opener.add_handler(urllib2.HTTPCookieProcessor(cookiejar))
resp = opener.open(req)
except Exception, e:
response = _502(env['PATH_INFO'], req.get_host(), e)
else:
response = HTTPResponse()
response.load_from_urllib(resp)
if cookiejar:
response.cookies = Cookie.BaseCookie()
for cookie in cookiejar:
if response.cookies.has_key(cookie.name):
del response.cookies[cookie.name]
response.cookies[cookie.name] = cookie.value
if cookie.expires:
response.cookies[cookie.name]['expires'] = cookie.expires
if cookie.domain:
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
resp.close()
return response
class MandayeApp(object):
def __init__(self):
self.env = None
self.dispatcher = None
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
self.env['mandaye.scheme'] = env['wsgi.url_scheme']
self.dispatcher = None
local_host = env['HTTP_HOST']
path_info = env['PATH_INFO']
if config.hosts.has_key(local_host):
for mapper in config.hosts[local_host]:
if re.match(mapper.get('path'), path_info):
if mapper.get('force_ssl'):
self.env['mandaye.scheme'] = 'https'
if mapper.has_key('target'):
self.dispatcher = Dispatcher(self.env, mapper.get('target'),
mapper.get('mapping'))
elif mapper.has_key('static'):
env['PATH_INFO'] = re.sub('^' + mapper.get('path'), '',
env['PATH_INFO'])
response = Cling(mapper.get('static')).__call__(env, start_response)
if not response:
if self.dispatcher:
response = self.on_request(start_response)
else:
response = self.on_response(start_response, _404(env['PATH_INFO']))
sql_session.commit()
except Exception, e:
sql_session.rollback()
response = self.on_response(start_response, _500(env['PATH_INFO'], "Unhandled exception",
exception=e, env=env))
finally:
sql_session.close()
return response
def _get_request(self):
""" Return a Mandaye HTTP Request
"""
headers = HTTPHeader()
if self.env.get('CONTENT_LENGTH'):
headers.addheader('Content-Length', self.env['CONTENT_LENGTH'])
if self.env.get('CONTENT_TYPE'):
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)
if self.env.has_key('HTTP_COOKIE'):
cookies = Cookie.BaseCookie(self.env['HTTP_COOKIE'])
else:
cookies = Cookie.BaseCookie()
if self.env['REQUEST_METHOD'] == 'POST':
msg = self.env['wsgi.input']
else:
msg = None
return HTTPRequest(cookies, headers, self.env['REQUEST_METHOD'], msg)
def on_request(self, start_response):
request = self._get_request()
# Calling the dispatcher hook for the request
request = self.dispatcher.mod_request(request)
if not request:
return self.on_response(start_response,
_500(self.env["PATH_INFO"], "Empty request"))
url = self.dispatcher.get_target_url()
if not url:
return self.on_response(start_response,
self.dispatcher.get_response(request))
response = get_response(self.env, request, url)
response = self.dispatcher.mod_response(request, response)
return self.on_response(start_response, response)
def on_response(self, start_response, response):
""" start_response: wsgi start_response
response: an instance of HTTPResponse """
response.headers.addsetcookies(response.cookies)
start_response('%d %s' % (response.code, response.reason),
response.headers.items())
return [response.msg]
class ServerHandler(WSGIHandler):
def log_request(self):
logging.info(self.format_request())
def serve():
"""Convenience function to immediately start a server instance."""
wsgi_app = SessionMiddleware(MandayeApp(), config.session_opts)
if config.ssl:
s = WSGIServer((config.host, config.port), wsgi_app,
keyfile=config.keyfile, certfile=config.certfile,
handler_class=ServerHandler)
else:
s = WSGIServer((config.host, config.port), wsgi_app,
handler_class=ServerHandler)
try:
s.serve_forever()
except KeyboardInterrupt:
s.stop()