2008-09-22 11:22:26 -05:00
|
|
|
# Authors:
|
|
|
|
# Jason Gerard DeRose <jderose@redhat.com>
|
|
|
|
#
|
|
|
|
# Copyright (C) 2008 Red Hat
|
|
|
|
# see file 'COPYING' for use and warranty information
|
|
|
|
#
|
|
|
|
# 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; version 2 only
|
|
|
|
#
|
|
|
|
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
|
|
"""
|
2008-10-07 21:07:16 -05:00
|
|
|
Package containing server backend.
|
2008-09-22 11:22:26 -05:00
|
|
|
"""
|
2009-01-30 21:53:32 -06:00
|
|
|
|
2009-10-26 06:16:18 -05:00
|
|
|
import traceback
|
2009-01-30 21:53:32 -06:00
|
|
|
from xmlrpclib import dumps, Fault
|
|
|
|
from ipalib import api
|
|
|
|
|
2009-01-31 00:46:51 -06:00
|
|
|
|
|
|
|
# This is a simple way to ensure that ipalib.api is only initialized
|
|
|
|
# when ipaserver is imported from within the Apache process:
|
2009-01-30 21:53:32 -06:00
|
|
|
try:
|
|
|
|
from mod_python import apache
|
2009-01-31 00:46:51 -06:00
|
|
|
api.bootstrap(context='server', debug=True, log=None)
|
2009-01-30 21:53:32 -06:00
|
|
|
api.finalize()
|
2009-01-31 00:46:51 -06:00
|
|
|
api.log.info('*** PROCESS START ***')
|
2009-10-26 06:16:18 -05:00
|
|
|
import ipawebui
|
|
|
|
ui = ipawebui.create_wsgi_app(api)
|
2009-01-30 21:53:32 -06:00
|
|
|
except ImportError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2009-11-02 15:16:27 -06:00
|
|
|
# START code from paste
|
|
|
|
# Red Hat does not hold the copyright to the following code. The following code
|
|
|
|
# is from paste:
|
2009-10-26 06:16:18 -05:00
|
|
|
# http://pythonpaste.org/
|
2009-11-02 15:16:27 -06:00
|
|
|
# Which in turn was based on Robert Brewer's modpython_gateway:
|
2009-10-26 06:16:18 -05:00
|
|
|
# http://projects.amor.org/misc/svn/modpython_gateway.py
|
|
|
|
|
|
|
|
class InputWrapper(object):
|
|
|
|
|
|
|
|
def __init__(self, req):
|
|
|
|
self.req = req
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def read(self, size=-1):
|
|
|
|
return self.req.read(size)
|
|
|
|
|
|
|
|
def readline(self, size=-1):
|
|
|
|
return self.req.readline(size)
|
|
|
|
|
|
|
|
def readlines(self, hint=-1):
|
|
|
|
return self.req.readlines(hint)
|
|
|
|
|
|
|
|
def __iter__(self):
|
|
|
|
line = self.readline()
|
|
|
|
while line:
|
|
|
|
yield line
|
|
|
|
# Notice this won't prefetch the next line; it only
|
|
|
|
# gets called if the generator is resumed.
|
|
|
|
line = self.readline()
|
|
|
|
|
|
|
|
|
|
|
|
class ErrorWrapper(object):
|
|
|
|
|
|
|
|
def __init__(self, req):
|
|
|
|
self.req = req
|
|
|
|
|
|
|
|
def flush(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def write(self, msg):
|
|
|
|
self.req.log_error(msg)
|
|
|
|
|
|
|
|
def writelines(self, seq):
|
|
|
|
self.write(''.join(seq))
|
|
|
|
|
|
|
|
|
|
|
|
bad_value = ("You must provide a PythonOption '%s', either 'on' or 'off', "
|
|
|
|
"when running a version of mod_python < 3.1")
|
|
|
|
|
|
|
|
|
|
|
|
class Handler(object):
|
|
|
|
|
|
|
|
def __init__(self, req):
|
|
|
|
self.started = False
|
|
|
|
|
|
|
|
options = req.get_options()
|
|
|
|
|
|
|
|
# Threading and forking
|
|
|
|
try:
|
|
|
|
q = apache.mpm_query
|
|
|
|
threaded = q(apache.AP_MPMQ_IS_THREADED)
|
|
|
|
forked = q(apache.AP_MPMQ_IS_FORKED)
|
|
|
|
except AttributeError:
|
|
|
|
threaded = options.get('multithread', '').lower()
|
|
|
|
if threaded == 'on':
|
|
|
|
threaded = True
|
|
|
|
elif threaded == 'off':
|
|
|
|
threaded = False
|
|
|
|
else:
|
|
|
|
raise ValueError(bad_value % "multithread")
|
|
|
|
|
|
|
|
forked = options.get('multiprocess', '').lower()
|
|
|
|
if forked == 'on':
|
|
|
|
forked = True
|
|
|
|
elif forked == 'off':
|
|
|
|
forked = False
|
|
|
|
else:
|
|
|
|
raise ValueError(bad_value % "multiprocess")
|
|
|
|
|
|
|
|
env = self.environ = dict(apache.build_cgi_env(req))
|
|
|
|
|
|
|
|
if 'SCRIPT_NAME' in options:
|
|
|
|
# Override SCRIPT_NAME and PATH_INFO if requested.
|
|
|
|
env['SCRIPT_NAME'] = options['SCRIPT_NAME']
|
|
|
|
env['PATH_INFO'] = req.uri[len(options['SCRIPT_NAME']):]
|
|
|
|
else:
|
|
|
|
env['SCRIPT_NAME'] = ''
|
|
|
|
env['PATH_INFO'] = req.uri
|
|
|
|
|
|
|
|
env['wsgi.input'] = InputWrapper(req)
|
|
|
|
env['wsgi.errors'] = ErrorWrapper(req)
|
|
|
|
env['wsgi.version'] = (1, 0)
|
|
|
|
env['wsgi.run_once'] = False
|
|
|
|
if env.get("HTTPS") in ('yes', 'on', '1'):
|
|
|
|
env['wsgi.url_scheme'] = 'https'
|
|
|
|
else:
|
|
|
|
env['wsgi.url_scheme'] = 'http'
|
|
|
|
env['wsgi.multithread'] = threaded
|
|
|
|
env['wsgi.multiprocess'] = forked
|
|
|
|
|
|
|
|
self.request = req
|
|
|
|
|
|
|
|
def run(self, application):
|
|
|
|
try:
|
|
|
|
result = application(self.environ, self.start_response)
|
|
|
|
for data in result:
|
|
|
|
self.write(data)
|
|
|
|
if not self.started:
|
|
|
|
self.request.set_content_length(0)
|
|
|
|
if hasattr(result, 'close'):
|
|
|
|
result.close()
|
|
|
|
except:
|
|
|
|
traceback.print_exc(None, self.environ['wsgi.errors'])
|
|
|
|
if not self.started:
|
|
|
|
self.request.status = 500
|
|
|
|
self.request.content_type = 'text/plain'
|
|
|
|
data = "A server error occurred. Please contact the administrator."
|
|
|
|
self.request.set_content_length(len(data))
|
|
|
|
self.request.write(data)
|
|
|
|
|
|
|
|
def start_response(self, status, headers, exc_info=None):
|
|
|
|
if exc_info:
|
|
|
|
try:
|
|
|
|
if self.started:
|
|
|
|
raise exc_info[0], exc_info[1], exc_info[2]
|
|
|
|
finally:
|
|
|
|
exc_info = None
|
|
|
|
|
|
|
|
self.request.status = int(status[:3])
|
|
|
|
|
|
|
|
for key, val in headers:
|
|
|
|
if key.lower() == 'content-length':
|
|
|
|
self.request.set_content_length(int(val))
|
|
|
|
elif key.lower() == 'content-type':
|
|
|
|
self.request.content_type = val
|
|
|
|
else:
|
|
|
|
self.request.headers_out.add(key, val)
|
|
|
|
|
|
|
|
return self.write
|
|
|
|
|
|
|
|
def write(self, data):
|
|
|
|
if not self.started:
|
|
|
|
self.started = True
|
|
|
|
self.request.write(data)
|
|
|
|
|
2009-11-02 15:16:27 -06:00
|
|
|
# END code from paste
|
2009-10-26 06:16:18 -05:00
|
|
|
|
|
|
|
|
|
|
|
def adapter(req, app):
|
2009-01-30 21:53:32 -06:00
|
|
|
if apache.mpm_query(apache.AP_MPMQ_IS_THREADED):
|
|
|
|
response = dumps(
|
2009-01-31 00:46:51 -06:00
|
|
|
Fault(3, 'Apache must use the forked model'),
|
|
|
|
methodresponse=True,
|
2009-01-30 21:53:32 -06:00
|
|
|
)
|
2009-10-26 06:16:18 -05:00
|
|
|
req.content_type = 'text/xml'
|
|
|
|
req.set_content_length(len(response))
|
|
|
|
req.write(response)
|
2009-01-30 21:53:32 -06:00
|
|
|
else:
|
2009-10-26 06:16:18 -05:00
|
|
|
Handler(req).run(app)
|
2009-01-30 21:53:32 -06:00
|
|
|
return apache.OK
|
2009-01-31 00:46:51 -06:00
|
|
|
|
|
|
|
|
2009-10-26 06:16:18 -05:00
|
|
|
def xmlrpc(req):
|
|
|
|
"""
|
|
|
|
mod_python handler for XML-RPC requests.
|
|
|
|
"""
|
|
|
|
return adapter(req, api.Backend.xmlserver)
|
|
|
|
|
|
|
|
|
2009-01-31 00:46:51 -06:00
|
|
|
def jsonrpc(req):
|
|
|
|
"""
|
|
|
|
mod_python handler for JSON-RPC requests (place holder).
|
|
|
|
"""
|
2009-10-26 06:16:18 -05:00
|
|
|
return adapter(req, api.Backend.jsonserver)
|
2009-01-31 00:46:51 -06:00
|
|
|
|
|
|
|
|
|
|
|
def webui(req):
|
|
|
|
"""
|
|
|
|
mod_python handler for web-UI requests (place holder).
|
|
|
|
"""
|
2009-10-26 06:16:18 -05:00
|
|
|
return adapter(req, ui)
|