diff options
Diffstat (limited to 'Mailman/Cgi/wsgi_app.py')
| -rw-r--r-- | Mailman/Cgi/wsgi_app.py | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/Mailman/Cgi/wsgi_app.py b/Mailman/Cgi/wsgi_app.py new file mode 100644 index 000000000..b7acd45fa --- /dev/null +++ b/Mailman/Cgi/wsgi_app.py @@ -0,0 +1,253 @@ +# -*- python -*- + +# Copyright (C) 2006 by the Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. + +import sys +STEALTH_MODE = False +# Shoul this be configurable in Defaults.py? + +def websafe(s): + return s + +import os +import StringIO +from email import message_from_string +from Mailman.configuration import config + +SCRIPTS = ['admin', 'admindb', 'confirm', 'create', + 'edithtml', 'listinfo', 'options', 'private', + 'rmlist', 'roster', 'subscribe'] +SLASH = '/' +NL2 = '\n\n' +CRLF2 = '\r\n\r\n' + +# WSGI to CGI wrapper. Mostly copied from scripts/driver. + +def mailman_app(environ, start_response): + """wrapper to *.py cgi commands""" + + global STEALTH_MODE, websafe + try: + try: + if not STEALTH_MODE: + from Mailman.Utils import websafe + except: + STEALTH_MODE = True + raise + + import logging + log = logging.getLogger('mailman.error') + + from Mailman import i18n + i18n.set_language(config.DEFAULT_SERVER_LANGUAGE) + + path = environ['PATH_INFO'] + paths = path.split(SLASH) + script = paths[1] + if script in SCRIPTS: + environ['SCRIPT_NAME'] = script + if len(paths) > 2: + environ['PATH_INFO'] = SLASH + SLASH.join(paths[2:]) + else: + environ['PATH_INFO'] = '' + # reverse proxy environment. + if environ.has_key('HTTP_X_FORWARDED_HOST'): + environ['HTTP_HOST'] = environ['HTTP_X_FORWARDED_HOST'] + if environ.has_key('HTTP_X_FORWARDED_FOR'): + environ['REMOTE_HOST'] = environ['HTTP_X_FORWARDED_FOR'] + modname = 'Mailman.Cgi.' + script + # Clear previous cookie before setting new one. + os.environ['HTTP_COOKIE'] = '' + for k, v in environ.items(): + os.environ[k] = str(v) + # Prepare for redirection. + save_stdin = sys.stdin + # CGI writes its output to sys.stdout, while wsgi app should + # return (list of) strings. + save_stdout = sys.stdout + save_stderr = sys.stderr + tmpstdout = StringIO.StringIO() + tmpstderr = StringIO.StringIO() + response = '' + try: + try: + sys.stdin = environ['wsgi.input'] + sys.stdout = tmpstdout + sys.stderr = tmpstderr + __import__(modname) + sys.modules[modname].main() + response = sys.stdout.getvalue() + finally: + sys.stdin = save_stdin + sys.stdout = save_stdout + sys.stderr = save_stderr + except SystemExit: + sys.stdout.write(tmpstdout.getvalue()) + if response: + try: + head, content = response.split(NL2, 1) + except ValueError: + head, content = response.split(CRLF2, 1) + m = message_from_string(head + CRLF2) + start_response('200 OK', m.items()) + return [content] + else: + # TBD: Error Code/Message + start_response('500 Server Error', []) + return '500 Internal Server Error' + else: + # TBD: Error Message + start_response('404 Not Found', []) + return '404 Not Found' + except: + start_response('200 OK', [('Content-Type', 'text/html')]) + retstring = print_traceback(log) + retstring +=print_environment(log) + return retstring + + + +# These functions are extracted and modified from scripts/driver. +# +# If possible, we print the error to two places. One will always be stdout +# and the other will be the log file if a log file was created. It is assumed +# that stdout is an HTML sink. +def print_traceback(log=None): + try: + import traceback + except ImportError: + traceback = None + try: + from Mailman.mm_cfg import VERSION + except ImportError: + VERSION = '<undetermined>' + + # Write to the log file first. + if log: + outfp = StringIO.StringIO() + + print >> outfp, '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@' + print >> outfp, '[----- Mailman Version: %s -----]' % VERSION + print >> outfp, '[----- Traceback ------]' + if traceback: + traceback.print_exc(file=outfp) + else: + print >> outfp, '[failed to import module traceback]' + print >> outfp, '[exc: %s, var: %s]' % sys.exc_info()[0:2] + # Don't use .exception() since that'll give us the exception twice. + # IWBNI we could print directly to the log's stream, or treat a log + # like an output stream. + log.error('%s', outfp.getvalue()) + + # return HTML sink. + htfp = StringIO.StringIO() + print >> htfp, """\ +<head><title>Bug in Mailman version %(VERSION)s</title></head> +<body bgcolor=#ffffff><h2>Bug in Mailman version %(VERSION)s</h2> +<p><h3>We're sorry, we hit a bug!</h3> +""" % locals() + if not STEALTH_MODE: + print >> htfp, '''<p>If you would like to help us identify the problem, +please email a copy of this page to the webmaster for this site with +a description of what happened. Thanks! + +<h4>Traceback:</h4><p><pre>''' + exc_info = sys.exc_info() + if traceback: + for line in traceback.format_exception(*exc_info): + print >> htfp, websafe(line) + else: + print >> htfp, '[failed to import module traceback]' + print >> htfp, '[exc: %s, var: %s]' %\ + [websafe(x) for x in exc_info[0:2]] + print >> htfp, '\n\n</pre></body>' + else: + print >> htfp, '''<p>Please inform the webmaster for this site of this +problem. Printing of traceback and other system information has been +explicitly inhibited, but the webmaster can find this information in the +Mailman error logs.''' + return htfp.getvalue() + + + +def print_environment(log=None): + try: + import os + except ImportError: + os = None + + if log: + outfp = StringIO.StringIO() + + # Write some information about our Python executable to the log file. + print >> outfp, '[----- Python Information -----]' + print >> outfp, 'sys.version =', sys.version + print >> outfp, 'sys.executable =', sys.executable + print >> outfp, 'sys.prefix =', sys.prefix + print >> outfp, 'sys.exec_prefix =', sys.exec_prefix + print >> outfp, 'sys.path =', sys.exec_prefix + print >> outfp, 'sys.platform =', sys.platform + + # Write the same information to the HTML sink. + htfp = StringIO.StringIO() + if not STEALTH_MODE: + print >> htfp, '''\ +<p><hr><h4>Python information:</h4> + +<p><table> +<tr><th>Variable</th><th>Value</th></tr> +<tr><td><tt>sys.version</tt></td><td> %s </td></tr> +<tr><td><tt>sys.executable</tt></td><td> %s </td></tr> +<tr><td><tt>sys.prefix</tt></td><td> %s </td></tr>' +<tr><td><tt>sys.exec_prefix</tt></td><td> %s </td></tr> +<tr><td><tt>sys.path</tt></td><td> %s </td></tr> +<tr><td><tt>sys.platform</tt></td><td> %s </td></tr> +</table>''' % (sys.version, sys.executable, sys.prefix, + sys.exec_prefix, sys.path, sys.platform) + + # Write environment variables to the log file. + if log: + print >> outfp, '[----- Environment Variables -----]' + if os: + for k, v in os.environ.items(): + print >> outfp, '\t%s: %s' % (k, v) + else: + print >> outfp, '[failed to import module os]' + + # Write environment variables to the HTML sink. + if not STEALTH_MODE: + print >> htfp, '''\ +<p><hr><h4>Environment variables:</h4> + +<p><table> +<tr><th>Variable</th><th>Value</th></tr> +''' + if os: + for k, v in os.environ.items(): + print >> htfp, '<tr><td><tt>' + websafe(k) + \ + '</tt></td><td>' + websafe(v) + \ + '</td></tr>' + print >> htfp, '</table>' + else: + print >> htfp, '<p><hr>[failed to import module os]' + + # Dump the log output + if log: + log.error('%s', outfp.getvalue()) + + return htfp.getvalue() |
