|
hunter
hunter at userfriendly.net
Thu Jan 18 07:34:59 EST 2001
I wrote to the list the other day, asking about converting a webserver
currently using Netscape Enterprise Server and python-1.5.2c to apache
running mod_python and python-1.5.2c due to the licensing being cost
probihitive. We use the "py-driver" within the webserver as nsapi to
push all our .py/.pd/.pc files to the users with netscape configured as
follows:
<snip>
<Object name="default">
NameTrans fn="pfx2dir" from="/cgi-bin"
dir="/disk2/websites/american/cgi-bin" na
me="cgi"
NameTrans fn="document-root" root="/disk2/websites/american/html"
PathCheck fn="unix-uri-clean"
PathCheck fn="check-acl" acl="default"
PathCheck fn="find-pathinfo"
PathCheck fn="find-index" index-names="index.pd"
ObjectType fn="type-by-extension"
ObjectType fn="force-type" type="text/plain"
Service method="(GET|HEAD|POST)" type="magnus-internal/py-driver"
fn="query-hand
ler" path="/disk2/ns-home/nsapi/pd/py-driver"
Service method="(GET|HEAD)" type="magnus-internal/imagemap"
fn="imagemap"
Service method="(GET|HEAD)" type="magnus-internal/directory"
fn="index-common"
Service method="(GET|HEAD|POST)" type="*~magnus-internal/*"
fn="send-file"
</snip>
which basically treats all calls to the .py/.pds as a cgi. Now, in
trying to convert over to apache and mod_python and do the same thing
within the apache configuration is where i am getting a bit confused. I
read through some of the documentation and i think the cgihandler might
be the way to handle this, but thought i would ask more senior python
programmers. I am a systems administrator and nowhere near as
experienced in python as 99% of the group here. So, i am looking for
advice and suggestions to see if a "proof of concept" can even be done.
I realize this might include some python module re-writes but if thats
fairly minimal i am still one step ahead rather than using netscape.
The py-driver being called in the above configuration looks like the
following:
#!/usr/local/bin/python
import sys, os
sys.path.insert(0, '/disk2/ns-home/nsapi/pd/')
sys.path.insert(1, '/disk2/common/')
sys.path.insert(2, '/disk2/ns-home/nsapi/mp/')
import pydriver
pydriver.topmain()
which imports pydriver which looks like the following:
#!/usr/local/bin/python
# -*- Python -*-
# PythonDriver main interpreter
#
# 960701 JM added HTML header override (ie: cookies)
#
# 960618 JM added Advert class
#
# common object layer imports
from col.exception.bopageflagexception import BOPageFlagException
# other imports
import pccache
__version__ = "1.5"
PD_Okay = "PD_Okay" # JM 960830
intSybFailFrac = 100 # one out of this number of sybase connect
fails will$
def pd_return(msg=''):
raise PD_Okay, msg
def get_func(dict, name):
if dict.has_key(name):
cb = dict[name]
if `type(cb)` == "<type 'function'>":
return cb
return None
class SmartPrint:
def __init__(self, real_stdout, headers=''):
self.need_headers = 1
self.headers = headers
self.real_stdout = real_stdout
## def write(self, msg):
## if self.need_headers:
## try:
## self.real_stdout.write(self.headers.show() + '\n')
## except AttributeError: ## XXXX
## self.real_stdout.write(self.headers)
## self.real_stdout.write(msg)
## self.need_headers = 0
# JM 960517
#
#
def get_hostip(environ):
try:
return 'IP:' + environ['REMOTE_ADDR']
except KeyError:
return 'IP:unknown' # XX ugh
def dump(environ=None):
if not environ:
from os import environ
list = environ.keys()
list.sort()
for k in list:
print "<b>%s</b> %s<BR>" % (k, environ[k])
# JM 960708
# use the cookie class to get the session ID, or return ''
#
def get_sessionid(cookiedict):
if cookiedict.has_key('ngs_sessionID'):
#
# Netsite: NGS session-id stuff installed
#
return cookiedict['ngs_sessionID'][:12]
elif cookiedict.has_key('Apache'):
#
# Apache: mod_cookie installed + enabled
#
return cookiedict['Apache']
else:
#
# no session-id thing
#
return ''
### if session ID not given,
### use client's IP address (XX debugging only!)
### JM 960517
## if environ.has_key('HTTP_COOKIE'):
## s = environ['HTTP_COOKIE'] # like "ngs_sessionID=23233885"
##
## if 'ngs_sessionID=' == s[:14]:
## s = s[14:14+12]
## else:
## s = get_hostip(environ) # XX no session id: error here?
##
## else:
## # dump(environ)
## s = get_hostip(environ) # XX no session id: error here?
##
## return s
def file_exists(path):
try:
open(path).close()
return 1
except IOError:
return 0
# Figure out a few things about what will happen, and put
# a few extra things in the Python search path.
#
# - take the original PD script path (ie:
'/www/test/htdocs/Tests/if.pd')
# (usually from the webserver's PATH_TRANSLATED variable).
#
# - turn it into the Python script path ('/www/test/htdocs/Tests/if.py')
# and then containing directory ('/www/test/htdocs/Tests/').
#
# - insert the PD directory in sys.path, so that PD support files
# (like 'cookie' and 'agent') will be found, and wont be overridden
# by user app files.
#
# - chdir to the user's script directory, so that app-local files
# can be found (sys.path contains '.') and written files will
# be relative to the script.
#
def script_setup(path):
import os, sys, string
if os.path.isdir(path):
if path[-1]!='/': path=path+'/'
path=path+'index.pd'
# replaced following line with a substitution to stop pydriver from
# displaying the py code when the URL has a .py. Set it back to .pd
# -MC 8/6/99
if path[-3:] == ".py":
path = path[:-3] + ".pd"
if os.environ.has_key('PATH_TRANSLATED'):
os.environ['PATH_TRANSLATED'] = path
templatepath = path
scriptpath = path[:-2] + "py"
scriptdir = path[:string.rfind(path, '/')]
pc_path = path[:-2] + "pc"
# make sure the PythonDriver dir is first on the path.
# (1st, else 'cookie.py' was being overridden)
# JM 961006
# commented out. py-driver now puts this at front of path.
# Mark Cain
#sys.path.insert(0, os.getcwd())
# raise KeyError, "vars=" + `locals()`
sys.path.append(scriptdir)
os.chdir(scriptdir) # JM 960827
return (templatepath, scriptpath, pc_path, scriptdir)
# allow project information to be overridden by the user,
# either by 'project.py' in the script directory,
# or in the one just above (XX provide search-path?)
#
def import_project(pathlist=['.'], modnamelist=['project']):
from uniondict import UnionDict
info = UnionDict() # union of all info
dicts
project = UnionDict() # union of *modules*
mod_dict = {} # temporary variable
scope
for file in modnamelist:
# load the module
#
exec "import "+file in mod_dict
module = mod_dict[file]
# add the module to the UnionDict,
# so that its functions *override* earlier ones
#
project.prepend(module.__dict__)
# add the 'info' dictionaries
# so that just-loaded defs *override* earlier ones
#
if module.__dict__.has_key('info'):
info.prepend(module.__dict__['info'])
project.info = info
return project
def html_print_techproblems():
# print "Location: http://162.133.26.95/goo.po"
# print "Content-length: 1"
# print "\n\n"
# import traceback
# html_print_exc(traceback)
try:
import socket
filNF = open('/disk2/flags/techproblems.html', 'r')
print filNF.read() % socket.gethostname()
filNF.close()
except:
print """
<table><tr>
<td align="center" width="312">
<img src="/images/banner.gif" width=312 height=45 border=0
alt="" al$
</td></tr></table>
"""
print "<br><font size=+3><b>We're sorry.</b>"
print "<p>We are repairing a technical problem. We apol$
def html_print_notfound(message=''):
print "Content-type: text/html\n\n"
try:
filNF = open('/disk2/flags/notfound.html', 'r')
print filNF.read()
filNF.close()
filNF.close()
except:
print """
<table><tr>
<td align="center" width="312">
<img src="/images/banner.gif" width=312 height=45 border=0
alt="" al$
</td></tr></table>
"""
print "<br><font size=+3><b>Not Found</b></font>"
print "<p>The requested file does not exist on our website."
def html_print_exc(traceback):
import sys
print "Content-type: text/html\n"
print "<font size=+3><b>internal error</b></font><P><PRE>",
traceback.print_exc(file=sys.stdout)
print "</PRE>"
def cgi_main():
import os, traceback
if not os.environ.has_key('PATH_TRANSLATED'):
print "Content-type: text/html\n"
print "PATH_TRANSLATED not given"
return
try:
main(os.environ['PATH_TRANSLATED'], os.environ)
except IOError, msg:
html_print_notfound(msg)
print "<!--"
html_print_exc(traceback)
print "-->"
except:
html_print_techproblems()
print "<!--"
html_print_exc(traceback)
print "-->"
def updatePC(pd_path, py_path, pc_path):
import os, codetemplate, time
dicPC = {}
# get stats on files
try:
tupPD = os.stat(pd_path)
tupPY = os.stat(py_path)
try:
try:
tupPC = os.stat(pc_path)
except:
tupPC = None
except:
raise IOError, "not found"
try:
# if pc file doesn't exist, or is older than either of the others,
then rec$
if (not tupPC or (tupPD[-2] > tupPC[-2]) or (tupPY[-2] >
tupPC[-2])):
pd_script = codetemplate.PD_Script(pd_path)
codPD = pd_script.code
dicPdVars = pd_script.dicPdVars
filTemp = open(py_path)
codPY = compile(filTemp.read(), py_path, "exec")
filTemp.close()
dicPC = { 'py': codPY,
'pd': codPD,
'dicPdVars': dicPdVars,
'pyDate': time.asctime(time.localtime(tupPY[-2])),
'pdDate': time.asctime(time.localtime(tupPD[-2])),
'pcDate': time.asctime(time.localtime(time.time()))
}
import marshal
try:
filPC = open(pc_path, 'w')
marshal.dump(dicPC, filPC)
filPC.close()
except IOError:
return
except:
#
# since this function runs outside of normal execution (as in
production)
# we add traceback error handling here. Else errors don't
propigate on th$
# normal route, having failed at this early point.
#
import sys, traceback
pd_except(py_path, sys.exc_type, sys.exc_value,
tb=traceback, globals=globals())
#
# Furthermore, no headers have been printed yet and "main"
execution is b$
# We need the basic header printed here.
#
#print "Content-type: text/html\n\n"
#
# Stop further execution by raising an error. Brings us back to
cgi-main $
# screen
#
raise "Failed"
def main(templatepath, environ=None):
import sys, string, cgi, os, traceback, ctsybase
dicPC = {} # dictionary containing pd and py code objects
blnInterpSrc = 0
blnTechProb = 0 # to note problem deserving of "tech problem"
message
if not environ:
environ=os.environ
(pd_path, py_path, pc_path, scriptdir) = script_setup( templatepath
)
if ((len (pd_path) > 13) and (pd_path[-13:] == "html/index.pd")):
import posixpath
HOMEFILE = '/disk2/flags/homelive.html'
if posixpath.exists(HOMEFILE) == 0:
import homedown
print homedown.pageVar
return
import marshal, codetemplate, agent
# get the 'project' module, but allow
# it to be overidden (unlike all other modules. Ex: cookies.py)
#
project = import_project(scriptdir)
from headers import Headers
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
# run-time stuff
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
finished = 0
headers = Headers(environ)
# print "info = " + `project.info`
if project.info.has_key('cookie_domain'):
headers.cookieSetDomain(project.info['cookie_domain'])
session_id = get_sessionid(headers.cookie)
# grab form variables
#
try:
# Old and outdated
if not os.environ.has_key('QUERY_STRING'):
os.environ['QUERY_STRING'] = ""
webvars = cgi.SvFormContentDict(environ=os.environ)
#webvars.__init__(os.environ)
#webvars = cgi.FieldStorage()
except:
webvars = {}
# grab Python global variables
# XXX?
script_dict = globals()
# rename a few variables
#
# XX
sp = SmartPrint(sys.stdout, headers)
script_dict.update({
'environ' : environ,
'session_id' : session_id,
'webvars' : webvars,
'headers' : headers,
'scriptpath' : py_path,
'project' : project,
'agent' : agent.open(environ)
})
for k in ['dbopen', 'pd_except']:
if project.has_key(k):
script_dict[k] = project[k]
# XX removed 961006 JM
# 'agent' : agent.open(environ),
# 'advert' : Advert(),
# merge globals and other vars into one dictionary
#
#for k in dict2.keys():
# script_dict[k] = dict2[k]
#
# del dict2 # dont need it anymore
# try to execute the Python script.
#
# call updatePC to compile pd and py file and write to pc file
# (do not call in production)
#updatePC(pd_path, py_path, pc_path)
try:
if (sys.modules.has_key('pccache')):
pccache = sys.modules['pccache']
dicPC = pccache.load(pc_path)
else:
filPC = open(pc_path, 'r')
dicPC = marshal.load(filPC)
filPC.close()
except IOError:
pd_script = codetemplate.PD_Script(pd_path)
blnInterpSrc = 1 # was unable to open compiled. Must interp.
else:
# load successful
# create "empty" PD_Script object and set its code object (no
processing $
pd_script = codetemplate.PD_Script()
pd_script.code = dicPC['pd']
if dicPC.has_key('dicPdVars'):
pd_script.dicPdVars = dicPC['dicPdVars']
script_dict['dicPdVars'] = pd_script.dicPdVars
try:
try:
try:
import pycodewrap
pycodewrap.begin(script_dict)
except BOPageFlagException, objException:
raise objException
except:
pass
if (blnInterpSrc):
f = open(py_path)
exec f in script_dict # old
f.close()
else:
exec (dicPC['py'] , script_dict) # new
try:
pycodewrap.end(script_dict)
except:
pass
except PD_Okay, msg:
# XX print msg somewhere?
pass
# catch and ignore broken pipe errors
except IOError, lstErr:
if lstErr[1] == 'Broken pipe':
pass
else:
raise lstErr
except ctsybase.error, lstErr:
if lstErr[0] == 'failed to connect to server':
blnTechProb = 1
import time
fltTime = time.time()
intTemp = int (( int(fltTime) + ((fltTime - int(fltTime)) *
10000)) %$
if intTemp == 0:
raise ctsybase.error + ": " + str(lstErr)
else:
pass
#raise "sybase error"
# catch BOPageFlagException to throw up alternate page
except BOPageFlagException, objException:
blnTechProb = 0
finished = 1 # XX run PD script after error
if sp.need_headers:
# was >> print "Content-type: text/html\n"
try:
print script_dict['headers'].show()
except AttributeError:
print script_dict['headers']
# headers were printed -- turn them off
#
sp.need_headers = 0
try:
filT = open(objException.strFile, 'r')
strText = filT.read()
filT.close()
except IOError:
objT = IOError("BOPageFlagException, can't open file '%s'" %
objExc$
raise objT
if objException.dicVariables:
strText = strText % objException.dicVariables
print strText
# if objException.blnTraceback is true, then do the traceback
anyhow
if objException.blnTraceback:
# does PY script have a custom exception handler?
# if so, use it; else use default: 'pd_except'.
#
cb = get_func(script_dict, '__except__')
if not cb:
cb = pd_except
finished = not cb(py_path, sys.exc_type, sys.exc_value,
tb=traceback, globals=globals())
# catch all for tracebacks
except:
blnTechProb = 1
finished = 0 # XX run PD script after error
if sp.need_headers:
# was >> print "Content-type: text/html\n"
try:
print script_dict['headers'].show()
except AttributeError:
print script_dict['headers']
# headers were printed -- turn them off
#
sp.need_headers = 0
# does PY script have a custom exception handler?
# if so, use it; else use default: 'pd_except'.
#
cb = get_func(script_dict, '__except__')
if not cb:
cb = pd_except
finished = not cb(py_path, sys.exc_type, sys.exc_value,
tb=traceback, globals=globals())
#f.close()
# did the PY script take care of everything? (IE: file download,
# exception handler doesnt want to show PD).
# If so, then just return -- *dont* execute PD script.
# JM 960829
if blnTechProb:
if sp.need_headers:
# was >> print "Content-type: text/html\n"
try:
print script_dict['headers'].show()
except AttributeError:
print script_dict['headers']
html_print_techproblems()
print "<!-- "
html_print_exc(traceback)
print "--> "
return
if finished or script_dict['headers'].finished():
return
# go ahead and print out HTTP headers now.
# if its whacked, just default it:
#
if sp.need_headers:
try:
print script_dict['headers'].show()
#print ' *** ' + dict['headers'].show() + ' *** '
except AttributeError:
print script_dict['headers']
try:
print pd_script.run(script_dict)
# catch and ignore broken pipe errors
except IOError, lstErr:
if lstErr[1] == 'Broken pipe':
pass
else:
raise lstErr
except:
import sys, traceback
pd_except(py_path, sys.exc_type, sys.exc_value,
tb=traceback, globals=globals())
html_print_techproblems()
print "<!-- "
html_print_exc(traceback)
print "--> "
return
def topmain():
import os, sys, posixpath
SFILE = '/disk2/flags/dblive.html'
error = ""
if posixpath.exists(SFILE) == 0:
import dbdown
pageVar = dbdown.pageVar
error = "DBBAD"
if error:
print pageVar
elif os.environ.has_key('PATH_TRANSLATED'):
import traceback
try:
cgi_main()
except:
print "<font size=+1>%s: problems</font><P>" %
"PythonDriver"
print "<PRE>",
traceback.print_exc()
print "</PRE>"
elif len(sys.argv) > 1:
import string
scriptpath = sys.argv[1]
os.environ['REQUEST_METHOD'] = 'GET'
os.environ['QUERY_STRING'] = string.joinfields( sys.argv[2:],
'&' )
main(scriptpath, os.environ)
else:
print "usage: py-driver <script> [GET-style args...]"
if __name__=="__main__":
main()
Any help would be GREATLY appreciated. I just need to mimic the netscape
behavior within apache, and i am having problems doing so. Maybe
mod_python isnt the way to go, but if anyone has any ideas for me to
try, i would be extremely greatful
Michael Weiner
Systems Administrator/Partner
The UserFriendly Network
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 2626 bytes
Desc: S/MIME Cryptographic Signature
Url : http://mailman.modpython.org/pipermail/mod_python/attachments/20010118/51182ff7/smime-0003.bin
|