mirror of https://github.com/evilhero/mylar
149 lines
4.8 KiB
Python
149 lines
4.8 KiB
Python
|
"""Wrapper for mod_wsgi, for use as a CherryPy HTTP server.
|
||
|
|
||
|
To autostart modwsgi, the "apache" executable or script must be
|
||
|
on your system path, or you must override the global APACHE_PATH.
|
||
|
On some platforms, "apache" may be called "apachectl" or "apache2ctl"--
|
||
|
create a symlink to them if needed.
|
||
|
|
||
|
|
||
|
KNOWN BUGS
|
||
|
==========
|
||
|
|
||
|
##1. Apache processes Range headers automatically; CherryPy's truncated
|
||
|
## output is then truncated again by Apache. See test_core.testRanges.
|
||
|
## This was worked around in http://www.cherrypy.org/changeset/1319.
|
||
|
2. Apache does not allow custom HTTP methods like CONNECT as per the spec.
|
||
|
See test_core.testHTTPMethods.
|
||
|
3. Max request header and body settings do not work with Apache.
|
||
|
##4. Apache replaces status "reason phrases" automatically. For example,
|
||
|
## CherryPy may set "304 Not modified" but Apache will write out
|
||
|
## "304 Not Modified" (capital "M").
|
||
|
##5. Apache does not allow custom error codes as per the spec.
|
||
|
##6. Apache (or perhaps modpython, or modpython_gateway) unquotes %xx in the
|
||
|
## Request-URI too early.
|
||
|
7. mod_wsgi will not read request bodies which use the "chunked"
|
||
|
transfer-coding (it passes REQUEST_CHUNKED_ERROR to ap_setup_client_block
|
||
|
instead of REQUEST_CHUNKED_DECHUNK, see Apache2's http_protocol.c and
|
||
|
mod_python's requestobject.c).
|
||
|
8. When responding with 204 No Content, mod_wsgi adds a Content-Length
|
||
|
header for you.
|
||
|
9. When an error is raised, mod_wsgi has no facility for printing a
|
||
|
traceback as the response content (it's sent to the Apache log instead).
|
||
|
10. Startup and shutdown of Apache when running mod_wsgi seems slow.
|
||
|
"""
|
||
|
|
||
|
import os
|
||
|
curdir = os.path.abspath(os.path.dirname(__file__))
|
||
|
import re
|
||
|
import sys
|
||
|
import time
|
||
|
|
||
|
import cherrypy
|
||
|
from cherrypy.test import helper, webtest
|
||
|
|
||
|
|
||
|
def read_process(cmd, args=""):
|
||
|
pipein, pipeout = os.popen4("%s %s" % (cmd, args))
|
||
|
try:
|
||
|
firstline = pipeout.readline()
|
||
|
if (re.search(r"(not recognized|No such file|not found)", firstline,
|
||
|
re.IGNORECASE)):
|
||
|
raise IOError('%s must be on your system path.' % cmd)
|
||
|
output = firstline + pipeout.read()
|
||
|
finally:
|
||
|
pipeout.close()
|
||
|
return output
|
||
|
|
||
|
|
||
|
if sys.platform == 'win32':
|
||
|
APACHE_PATH = "httpd"
|
||
|
else:
|
||
|
APACHE_PATH = "apache"
|
||
|
|
||
|
CONF_PATH = "test_mw.conf"
|
||
|
|
||
|
conf_modwsgi = r"""
|
||
|
# Apache2 server conf file for testing CherryPy with modpython_gateway.
|
||
|
|
||
|
ServerName 127.0.0.1
|
||
|
DocumentRoot "/"
|
||
|
Listen %(port)s
|
||
|
|
||
|
AllowEncodedSlashes On
|
||
|
LoadModule rewrite_module modules/mod_rewrite.so
|
||
|
RewriteEngine on
|
||
|
RewriteMap escaping int:escape
|
||
|
|
||
|
LoadModule log_config_module modules/mod_log_config.so
|
||
|
LogFormat "%%h %%l %%u %%t \"%%r\" %%>s %%b \"%%{Referer}i\" \"%%{User-agent}i\"" combined
|
||
|
CustomLog "%(curdir)s/apache.access.log" combined
|
||
|
ErrorLog "%(curdir)s/apache.error.log"
|
||
|
LogLevel debug
|
||
|
|
||
|
LoadModule wsgi_module modules/mod_wsgi.so
|
||
|
LoadModule env_module modules/mod_env.so
|
||
|
|
||
|
WSGIScriptAlias / "%(curdir)s/modwsgi.py"
|
||
|
SetEnv testmod %(testmod)s
|
||
|
"""
|
||
|
|
||
|
|
||
|
class ModWSGISupervisor(helper.Supervisor):
|
||
|
"""Server Controller for ModWSGI and CherryPy."""
|
||
|
|
||
|
using_apache = True
|
||
|
using_wsgi = True
|
||
|
template=conf_modwsgi
|
||
|
|
||
|
def __str__(self):
|
||
|
return "ModWSGI Server on %s:%s" % (self.host, self.port)
|
||
|
|
||
|
def start(self, modulename):
|
||
|
mpconf = CONF_PATH
|
||
|
if not os.path.isabs(mpconf):
|
||
|
mpconf = os.path.join(curdir, mpconf)
|
||
|
|
||
|
f = open(mpconf, 'wb')
|
||
|
try:
|
||
|
output = (self.template %
|
||
|
{'port': self.port, 'testmod': modulename,
|
||
|
'curdir': curdir})
|
||
|
f.write(output)
|
||
|
finally:
|
||
|
f.close()
|
||
|
|
||
|
result = read_process(APACHE_PATH, "-k start -f %s" % mpconf)
|
||
|
if result:
|
||
|
print(result)
|
||
|
|
||
|
# Make a request so mod_wsgi starts up our app.
|
||
|
# If we don't, concurrent initial requests will 404.
|
||
|
cherrypy._cpserver.wait_for_occupied_port("127.0.0.1", self.port)
|
||
|
webtest.openURL('/ihopetheresnodefault', port=self.port)
|
||
|
time.sleep(1)
|
||
|
|
||
|
def stop(self):
|
||
|
"""Gracefully shutdown a server that is serving forever."""
|
||
|
read_process(APACHE_PATH, "-k stop")
|
||
|
|
||
|
|
||
|
loaded = False
|
||
|
def application(environ, start_response):
|
||
|
import cherrypy
|
||
|
global loaded
|
||
|
if not loaded:
|
||
|
loaded = True
|
||
|
modname = "cherrypy.test." + environ['testmod']
|
||
|
mod = __import__(modname, globals(), locals(), [''])
|
||
|
mod.setup_server()
|
||
|
|
||
|
cherrypy.config.update({
|
||
|
"log.error_file": os.path.join(curdir, "test.error.log"),
|
||
|
"log.access_file": os.path.join(curdir, "test.access.log"),
|
||
|
"environment": "test_suite",
|
||
|
"engine.SIGHUP": None,
|
||
|
"engine.SIGTERM": None,
|
||
|
})
|
||
|
return cherrypy.tree(environ, start_response)
|
||
|
|