Skip to content

Instantly share code, notes, and snippets.

@jedie
Created September 1, 2011 16:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jedie/1186632 to your computer and use it in GitHub Desktop.
Save jedie/1186632 to your computer and use it in GitHub Desktop.
Detect web handler: mod_wsgi, fast_CGI, mod_python or CGI and display many informations
#!/usr/bin/env python
# coding: utf-8
"""
Python web handler test
~~~~~~~~~~~~~~~~~~~~~~~
Detect web handler: mod_wsgi, fast_CGI, mod_python or CGI and display many informations
You should check if the shebang is ok for your environment!
some examples:
#!/usr/bin/env python
#!/usr/bin/env python2.4
#!/usr/bin/env python2.5
#!/usr/bin/python
#!/usr/bin/python2.4
#!/usr/bin/python2.5
#!C:\python\python.exe
TODO:
* mod_python logs same lines very often, why?
* update ModuleInfo()
Tested with mod_rewrite and this .htaccess:
==========================================================================
# Enable execution of scripts (not needed in every cases)
# http://httpd.apache.org/docs/2.0/mod/core.html#options
#Options +ExecCGI
#-----------------------------------------------------------------------
#
# Activate script Handler (not needed in every cases)
# http://httpd.apache.org/docs/2.0/mod/mod_mime.html#addhandler
#
# libapache2-mod-wsgi
#AddHandler wsgi-script .py
# Old libapache2-mod-fastcgi Apache module:
#AddHandler fastcgi-script .py
# New libapache2-mod-fcgid Apache module:
#AddHandler fcgid-script .py
# libapache2-mod-python
#AddHandler mod_python .py
#PythonHandler python_test
#PythonDebug on
# normal CGI
#AddHandler cgi-script .py
#-----------------------------------------------------------------------
# http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ python_test.py/$1 [QSA,L]
==========================================================================
:copyleft: 2011 by Jens Diemer
:license: GNU GPL v3 or above
"""
from cgi import escape
import StringIO
import atexit
import glob
import imp
import logging
import os
import sys
import time
import traceback
try:
import pwd
except Exception, err:
pwd_availabe = err
else:
pwd_availabe = True
SCRIPT_FILENAME = os.path.abspath(__file__)
BASE_NAME = os.path.splitext(os.path.basename(SCRIPT_FILENAME))[0]
BASE_PATH = os.path.dirname(SCRIPT_FILENAME)
LOGFILE = os.path.join(BASE_PATH, BASE_NAME + ".log")
log = logging.getLogger(BASE_NAME)
handler = logging.FileHandler(filename=LOGFILE)
formatter = logging.Formatter('%(asctime)s PID:%(process)d %(levelname)s: %(message)s')
handler.setFormatter(formatter)
log.addHandler(handler)
log.setLevel(logging.DEBUG)
log.info("start up %r" % __file__)
atexit.register(log.info, "-- END --")
MOD_WSGI = "mod_WSGI"
FASTCGI = "fast_CGI"
MOD_PYTHON = "mod_Python"
CGI = "CGI"
class RunningType(object):
RUNNING_TYPE = None
@classmethod
def _set(self, run_type):
log.info("Detect run type: %s" % run_type)
self.RUNNING_TYPE = run_type
@classmethod
def set_mod_wsgi(self):
self._set(MOD_WSGI)
@classmethod
def set_fastcgi(self):
self._set(FASTCGI)
@classmethod
def set_mod_python(self):
self._set(MOD_PYTHON)
@classmethod
def set_cgi(self):
self._set(CGI)
def tail_log(max=20):
""" returns the last >max< lines, from LOGFILE """
try:
f = file(LOGFILE, "r")
seekpos = -80 * max
try:
f.seek(seekpos, 2)
except IOError: # File is to small
pass
last_lines = "".join(f.readlines()[-max:])
f.close()
return last_lines
except:
return "Error, getting %r content:\n%s" % (
LOGFILE, traceback.format_exc()
)
def get_apache_load_files(path):
""" Simply get a list of all *.load files from the path. """
modules = []
for item in os.listdir(path):
filepath = os.path.join(path, item)
if os.path.isfile(filepath):
name, ext = os.path.splitext(item)
if ext == ".load" and name not in modules:
modules.append(name)
return modules
class ModuleInfo(object):
"""
Auflisten aller installierten Module
"""
def __init__(self):
self.glob_suffixes = self.get_suffixes()
filelist = self.scan()
self.modulelist = self.test(filelist)
def get_suffixes(self):
"""
Liste aller Endungen aufbereitet für glob()
"""
suffixes = ["*" + i[0] for i in imp.get_suffixes()]
suffixes = "[%s]" % "|".join(suffixes)
return suffixes
def get_files(self, path):
"""
Liefert alle potentiellen Modul-Dateien eines Verzeichnisses
"""
files = []
for suffix in self.glob_suffixes:
searchstring = os.path.join(path, suffix)
files += glob.glob(searchstring)
return files
def scan(self):
"""
Verzeichnisse nach Modulen abscannen
"""
filelist = []
pathlist = sys.path
for path_item in pathlist:
if not os.path.isdir(path_item):
continue
for filepath in self.get_files(path_item):
filename = os.path.split(filepath)[1]
if filename.startswith(".") or filename.startswith("_"):
continue
if filename == "__init__.py":
continue
filename = os.path.splitext(filename)[0]
if filename in filelist:
continue
else:
filelist.append(filename)
return filelist
def test(self, filelist):
"""
Testet ob alle gefunden Dateien auch als Modul
importiert werden können
"""
modulelist = []
for filename in filelist:
try:
imp.find_module(filename)
except:
continue
modulelist.append(filename)
modulelist.sort()
return modulelist
def get_pylucid_ver():
try:
from pylucid_project import VERSION_STRING
return VERSION_STRING
except Exception, err:
return "[Error: %s]" % err
def get_ip_info():
try:
import socket
domain_name = socket.getfqdn()
except Exception, err:
domain_name = "[Error: %s]" % err
ip_addresses = "-"
else:
try:
ip_addresses = ", ".join(socket.gethostbyname_ex(domain_name)[2])
except Exception, err:
ip_addresses = "[Error: %s]" % err
return ip_addresses, domain_name
def get_userinfo():
uid = "???"
username = "???"
try:
uid = os.getuid()
except Exception, err:
uid = "[Error: %s]" % err
username = "-"
if pwd_availabe != True:
return uid, pwd_availabe
try:
username = pwd.getpwuid(uid)
except Exception, err:
username = "[Error: %s]" % err
return uid, username
def info_app(environ, start_response):
"""
Fallback application, used to display the user some information, why the
main app doesn't start.
"""
log.info("info_app() - START")
start_response('200 OK', [('Content-Type', 'text/html')])
yield "<h1>Python Test Web App</h1>"
#_________________________________________________________________________
yield "<p>run as: <strong>"
if RunningType.RUNNING_TYPE is None:
yield "unknown!"
else:
yield RunningType.RUNNING_TYPE
if RunningType.RUNNING_TYPE is MOD_WSGI:
try:
from mod_wsgi import version
yield " v%s" % ".".join([str(i) for i in version])
except ImportError, err:
yield " - %s" % err
elif RunningType.RUNNING_TYPE is MOD_PYTHON:
try:
# http://www.dscpl.com.au/wiki/ModPython/Articles/GettingModPythonWorking
import mod_python
except ImportError:
pass
else:
yield " v%s" % getattr(mod_python, "version", "<3.2")
try:
import mod_python.psp
except ImportError, err:
yield " (import mod_python.psp error: %s)" % err
else:
yield " (mod_python.psp exists)"
yield "</stong></p>"
#_________________________________________________________________________
yield "<h2>System informations:</h2>"
yield "<table>"
yield '<tr><th>Python version</th><td>%s</td></tr>' % sys.version
yield '<tr><th>sys.prefix</th><td>%s</td></tr>' % sys.prefix
yield '<tr><th>__name__</th><td>%s</td></tr>' % __name__
yield '<tr><th>os.uname</th><td>%s</td></tr>' % " ".join(os.uname())
yield '<tr><th>script file</th><td>%s</td></tr>' % SCRIPT_FILENAME
yield '<tr><th>PID</th><td>%s</td></tr>' % os.getpid()
yield '<tr><th>UID / pwd_info</th><td>%s / %s</td></tr>' % get_userinfo()
yield '<tr><th>GID</th><td>%s</td></tr>' % os.getgid()
ips, domain = get_ip_info()
yield '<tr><th>IPs</th><td>%s</td></tr>' % ips
yield '<tr><th>domain</th><td>%s</td></tr>' % domain
yield "</table>"
#_________________________________________________________________________
yield "<h2>Apache modules:</h2>"
try:
path = "/etc/apache2/mods-enabled"
yield "<p><small>(*.load files from %r)</small><br />" % path
modules = get_apache_load_files(path)
yield ", ".join(sorted(modules))
yield "</p>"
except:
yield "Error: %s" % traceback.format_exc()
#_________________________________________________________________________
yield "<h2>Environments</h2>"
if RunningType.RUNNING_TYPE == MOD_PYTHON:
env_name = "mod_python"
else:
env_name = "WSGI"
yield "<h3>%s Environment</h3>" % env_name
yield "<table>"
for k, v in sorted(environ.items()):
yield '<tr><th>%s</th><td>%s</td></tr>' % (escape(k), escape(repr(v)))
yield "</table>"
yield "<h3>OS Environment</h3>"
yield "<table>"
for k, v in sorted(os.environ.items()):
yield '<tr><th>%s</th><td>%s</td></tr>' % (escape(k), escape(v))
yield "</table>"
#_________________________________________________________________________
yield "<h2>python sys.path</h2>"
yield "<ul>"
for path in sys.path:
yield "<li>%s</li>" % path
yield "</ul>"
#_________________________________________________________________________
yield "<h2>Existing Python modules:</h2>"
m = ModuleInfo()
yield "<p>%s</p>" % ", ".join(m.modulelist)
yield "<h2>Last lines in %s</h2>" % LOGFILE
yield "<pre>%s</pre>" % tail_log()
yield "<hr />"
yield "<p>-- END --</p>"
log.info("info_app() - END")
log.debug("__name__ == %s" % repr(__name__))
if __name__.startswith('_mod_wsgi_'):
log.info("We are under mod_wsgi!")
# https://code.google.com/p/modwsgi/wiki/TipsAndTricks#Determining_If_Running_Under_mod_wsgi
try:
RunningType.set_mod_wsgi()
application = info_app
except:
log.error(traceback.format_exc())
raise
elif __name__.startswith('_mp_'):
log.info("We are under mod_python!")
try:
RunningType.set_mod_python()
from mod_python import apache
def fake_start_reponse(*args, **kwargs):
pass
def handler(req):
req.content_type = "text/html"
req.send_http_header()
for line in info_app(req.subprocess_env, fake_start_reponse):
req.write(line)
return apache.OK
except:
log.error(traceback.format_exc())
raise
elif __name__ == "__main__": # fast_CGI or normal CGI
if "CGI" in os.environ.get("GATEWAY_INTERFACE", ""):
try:
RunningType.set_cgi()
import cgitb; cgitb.enable()
from wsgiref.handlers import CGIHandler
CGIHandler().run(info_app)
except:
tb = traceback.format_exc()
log.error(tb)
print "Content-Type: text/html;charset=utf-8\n"
print "<pre>%s</pre>" % tb
else:
# fast_CGI or mod_python?
try:
RunningType.set_fastcgi()
from flup.server.fcgi import WSGIServer
WSGIServer(info_app).run()
except:
log.error(traceback.format_exc())
raise
else:
log.error("Unknown __name__ value!")
@jedie
Copy link
Author

jedie commented Sep 2, 2011

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment