|
[Webware-checkins] r7120 - in Webware/trunk/CGIWrapper: . Docs
Examples
From: <updates@we...> - 2007-12-09 12:24
|
Author: chrisz
Date: Sun Dec 9 05:24:09 2007
New Revision: 7120
Added:
Webware/trunk/CGIWrapper/_accessDenied.py (contents, props changed)
Webware/trunk/CGIWrapper/_viewError.py (contents, props changed)
Removed:
Webware/trunk/CGIWrapper/Docs/RelNotes-0.8.phtml
Modified:
Webware/trunk/CGIWrapper/ (props changed)
Webware/trunk/CGIWrapper/AdminPage.py
Webware/trunk/CGIWrapper/CGIWrapper.py
Webware/trunk/CGIWrapper/Docs/RelNotes-X.Y.phtml
Webware/trunk/CGIWrapper/Docs/SampleAdmin.html
Webware/trunk/CGIWrapper/Docs/SampleError.html
Webware/trunk/CGIWrapper/Docs/UsersGuide.phtml
Webware/trunk/CGIWrapper/Examples/Colors.py
Webware/trunk/CGIWrapper/Examples/Directory.py
Webware/trunk/CGIWrapper/Examples/FormTest.py
Webware/trunk/CGIWrapper/Examples/Hello.py
Webware/trunk/CGIWrapper/Examples/Introspect.py
Webware/trunk/CGIWrapper/Examples/Time.py
Webware/trunk/CGIWrapper/Examples/View.py
Webware/trunk/CGIWrapper/_admin.py
Webware/trunk/CGIWrapper/_dumpCSV.py
Webware/trunk/CGIWrapper/_dumpErrors.py
Webware/trunk/CGIWrapper/_showConfig.py
Log:
Clean-up of CGIWrapper for the upcoming 1.0 release.
Modified: Webware/trunk/CGIWrapper/AdminPage.py
==============================================================================
--- Webware/trunk/CGIWrapper/AdminPage.py (original)
+++ Webware/trunk/CGIWrapper/AdminPage.py Sun Dec 9 05:24:09 2007
@@ -1,14 +1,13 @@
-import os, string, sys
class AdminPage:
- """
- AdminPage is the abstract superclass of all CGI Wrapper administration CGI classes.
+ """AdminPage
- Subclasses typically override title() and writeBody(), but may customize other methods.
+ This is the abstract superclass of all CGI Wrapper administration CGI
+ classes. Subclasses typically override title() and writeBody(), but may
+ customize other methods. Subclasses use self._var for the various vars
+ that are passed in from CGI Wrapper and self.write() and self.writeln().
- Subclasses use self._var for the various vars that are passed in from CGI Wrapper
- and self.write() and self.writeln().
"""
@@ -16,7 +15,7 @@
def __init__(self, vars):
for name in vars.keys():
- setattr(self, '_'+name, vars[name])
+ setattr(self, '_' + name, vars[name])
self._vars = vars
@@ -27,7 +26,7 @@
self.writeHeader()
self.writeBody()
self.writeFooter()
- return string.join(self._html, '')
+ return ''.join(self._html)
## Utility methods ##
@@ -45,11 +44,14 @@
## Content methods ##
def writeHeader(self):
- self.writeln('''<html>
- <head>
- <title>%s</title>
- </head>
- <body %s><table align=center><tr><td>''' % (self.title(), self.bodyTags()))
+ self.writeln('''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <title>%s</title>
+ </head>
+ <body %s>
+ <table align="center" bgcolor="white"><tr><td>''' % (
+ self.title(), self.bodyTags()))
self.writeBanner()
self.writeToolbar()
@@ -57,23 +59,27 @@
raise NotImplementedError, 'Should be overridden in a subclass'
def writeFooter(self):
- self.writeln('<p><br><hr></table></body></html>')
+ self.writeln('''
+ <hr>
+ <div align="center" style="font-size:small">Webware for Python</div>
+ </td></tr></table>
+ </body>
+</html>''')
def title(self):
raise NotImplementedError, 'Should be overridden in a subclass'
def bodyTags(self):
- return 'color=black bgcolor=white'
+ return 'text="black" bgcolor="#555555"'
def writeBanner(self):
- self.writeln('''<table align=center bgcolor=darkblue cellpadding=5 cellspacing=0 width=100%%>
- <tr><td align=center>
- <font face="Tahoma, Arial, Helvetica" color=white><b>
- CGI Wrapper
- <br><font size=+2>%s</font>
- </b></font>
+ self.writeln('''
+ <table align="center" bgcolor="#202080" cellpadding="5" cellspacing="0" width="100%%">
+ <tr><td align="center" style="color:white;font-weight:bold;font-family:Tahoma,Verdana,Arial,Helvetica,sans-serif">
+ <div style="font-size:14pt">CGI Wrapper</div>
+ <div style="font-size:16pt">%s</div>
</td></tr>
- </table><p>''' % self.title())
+ </table>''' % self.title())
def writeToolbar(self):
pass
Modified: Webware/trunk/CGIWrapper/CGIWrapper.py
==============================================================================
--- Webware/trunk/CGIWrapper/CGIWrapper.py (original)
+++ Webware/trunk/CGIWrapper/CGIWrapper.py Sun Dec 9 05:24:09 2007
@@ -1,73 +1,49 @@
#!/usr/bin/env python
-# CGIWrapper.py
-# Webware for Python
-# See the CGIWrapper.html documentation for more information.
+"""CGIWrapper.py
+Webware for Python
+
+See the CGIWrapper.html documentation for more information.
+
+"""
# We first record the starting time, in case we're being run as a CGI script.
-from time import time, localtime, gmtime, asctime
+from time import time, localtime, asctime
serverStartTime = time()
# Some imports
-import cgi, os, sys, traceback, random
+import cgi, os, sys, traceback
from types import DictType, FloatType
+from random import randint
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO
if '' not in sys.path:
sys.path.insert(0, '')
+from Properties import version
+
try:
import WebUtils
-except:
+except ImportError:
sys.path.append(os.path.abspath('..'))
import WebUtils
from WebUtils.HTMLForException import HTMLForException
-import MiscUtils
from MiscUtils.NamedValueAccess import NamedValueAccess
-from UserDict import UserDict
-
-# @@ 2000-05-01 ce:
-# PROBLEM: For reasons unknown, target scripts cannot import modules of
-# the WebUtils package *unless* they are already imported.
-# TEMP SOLUTION: Import all the modules.
-# TO DO: distill this problem and post to comp.lang.python for help.
-# begin
-import WebUtils.Cookie
-import WebUtils.HTTPStatusCodes
-# end
-
-
-# Beef up UserDict with the NamedValueAccess base class and custom versions of
-# hasValueForKey() and valueForKey(). This all means that UserDict's (such as
-# os.environ) are key/value accessible. At some point, this probably needs to
-# move somewhere else as other Webware components will need this "patch".
-# @@ 2000-01-14 ce: move this
-#
-if not NamedValueAccess in UserDict.__bases__:
- UserDict.__bases__ += (NamedValueAccess,)
-
- def _UserDict_hasValueForKey(self, key):
- return self.has_key(key)
-
- def _UserDict_valueForKey(self, key, default=None):
- return self.get(key, default)
-
- setattr(UserDict, 'hasValueForKey', _UserDict_hasValueForKey)
- setattr(UserDict, 'valueForKey', _UserDict_valueForKey)
-
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
class CGIWrapper(NamedValueAccess):
- """
- A CGIWrapper executes a target script and provides various services for
- the both the script and website developer and administrator.
+ """The CGI Wrapper class.
+
+ A CGI wrapper executes a target script and provides various services
+ for both the script and website developer and the administrator.
See the CGIWrapper.html documentation for full information.
+
"""
@@ -80,14 +56,14 @@
## Configuration ##
def defaultConfig(self):
- """
- Returns a dictionary with the default
- configuration. Subclasses could override to customize
- the values or where they're taken from.
- """
+ """Return a dictionary with the default configuration.
+
+ Subclasses could override to customize the values
+ or where they're taken from.
+ """
return {
- 'ScriptsHomeDir': 'Scripts',
+ 'ScriptsHomeDir': 'Examples',
'ChangeDir': 1,
'ExtraPaths': [],
'ExtraPathsIndex': 1,
@@ -117,54 +93,65 @@
'Reply-to': 'webware@...',
'Content-type': 'text/html',
'Subject': 'Error'
- }
+ },
+ 'AdminRemoteAddr': ['127.0.0.1']
}
def configFilename(self):
- """Used by userConfig()."""
- return 'Config.dict'
+ """Return the filename of the optional configuration file."""
+ return 'CGIWrapper.config'
def userConfig(self):
- """
- Returns the user config overrides found in the
- optional config file, or {} if there is no such
- file. The config filename is taken from
- configFilename().
- """
+ """Return a dictionary with the user configuration.
+
+ This are overrides found in the optional configuration file,
+ or {} if there is no such file. The config filename is taken
+ from configFilename().
+ """
try:
- file = open(self.configFilename())
+ f = open(self.configFilename())
except IOError:
return {}
else:
- config = eval(file.read())
- file.close()
- assert type(config) is DictType
+ config = f.read()
+ try:
+ dict
+ except NameError: # Python < 2.2
+ config = eval(config)
+ else:
+ config = eval('dict(%s)' % config)
+ f.close()
+ assert isinstance(config, DictType)
return config
def config(self):
- """
- Returns the configuration for the wrapper which is a
- combination of defaultConfig() and userConfig(). This
- method does no caching.
+ """Return the configuration for the CGIWrapper.
+
+ This is a combination of defaultConfig() and userConfig().
+ This method does no caching.
+
"""
config = self.defaultConfig()
config.update(self.userConfig())
return config
def setting(self, name):
- """Returns the value of a particular setting in the configuration."""
+ """Return the value of a particular setting in the configuration."""
return self._config[name]
## Utilities ##
+ def docType(self):
+ return docType()
+
def makeHeaders(self):
- """Returns a default header dictionary containing {'Content-type': 'text/html'}."""
+ """Return a default header dictionary containing {'Content-type': 'text/html'}."""
return {'Content-type': 'text/html'}
def makeFieldStorage(self):
- """Returns a default field storage object created from the cgi module."""
+ """Return a default field storage object created from the cgi module."""
return cgi.FieldStorage()
def enhanceThePath(self):
@@ -173,40 +160,52 @@
sys.path[extraPathsIndex:extraPathsIndex] = self.setting('ExtraPaths')
def requireEnvs(self, names):
- """
- Checks that given environment variable names exist. If
- they don't, a basic HTML error message is printed and
- we exit.
+ """Check that given environment variable names exist.
+
+ If they don't, a basic HTML error message is printed and we exit.
+
"""
badNames = []
for name in names:
if not self._environ.has_key(name):
badNames.append(name)
if badNames:
- print 'Content-type: text/html\n'
- print '<html><body>'
+ print 'Content-type: text/html'
+ print
+ print docType()
+ print '<html><head><title>Error</title></head><body>'
print '<p>', 'ERROR: Missing', ', '.join(badNames), '</p>'
print '</body></html>'
sys.exit(0)
def scriptPathname(self):
+ """Return the full pathname of the target script.
+
+ Scripts that start with an underscore are special -- they run
+ out of the same directory as the CGI Wrapper and are typically
+ CGI Wrapper support scripts.
+
"""
- Returns the full pathname of the target
- script. Scripts that start with an underscore are
- special--they run out of the same directory as the CGI
- Wrapper and are typically CGI Wrapper support
- scripts.
- """
- pathname = os.path.split(self._environ['SCRIPT_FILENAME'])[0] # remove the CGI Wrapper's filename part
+ # remove the CGI Wrapper's filename part
+ pathname = os.path.split(self._environ['SCRIPT_FILENAME'])[0]
filename = self._environ['PATH_INFO'][1:]
ext = os.path.splitext(filename)[1]
if ext == '':
# No extension - we assume a Python CGI script.
if filename[0] == '_':
# Underscores denote private scripts packaged with CGI Wrapper, such as '_admin.py'.
+ if self.setting('AdminRemoteAddr'):
+ # Users with the wrong remote address are redirected to the access denied script.
+ self.requireEnvs(['REMOTE_ADDR'])
+ remoteAddr = self._environ['REMOTE_ADDR'] + '.'
+ for addr in self.setting('AdminRemoteAddr'):
+ if remoteAddr.startswith(addr + '.'):
+ break
+ else:
+ filename = '_accessDenied'
filename = os.path.join(pathname, filename + '.py')
else:
- # all other scripts are based in the directory named by the 'ScriptsHomeDir' setting.
+ # All other scripts are based in the directory named by the 'ScriptsHomeDir' setting.
filename = os.path.join(pathname, self.setting('ScriptsHomeDir'), filename + '.py')
self._servingScript = 1
else:
@@ -217,41 +216,44 @@
return filename
def writeScriptLog(self):
- """
- Writes an entry to the script log file. Uses settings
- ScriptLogFilename and ScriptLogColumns.
+ """Write an entry to the script log file.
+
+ Uses settings ScriptLogFilename and ScriptLogColumns.
+
"""
filename = self.setting('ScriptLogFilename')
if os.path.exists(filename):
- file = open(filename, 'a')
+ f = open(filename, 'a')
else:
- file = open(filename, 'w')
- file.write(','.join(self.setting('ScriptLogColumns')) + '\n')
+ f = open(filename, 'w')
+ f.write(','.join(self.setting('ScriptLogColumns')) + '\n')
values = []
for column in self.setting('ScriptLogColumns'):
value = self.valueForName(column)
- if type(value) is FloatType:
- value = '%0.2f' % value # might need more flexibility in the future
+ if isinstance(value, FloatType):
+ value = '%0.4f' % value # might need more flexibility in the future
else:
value = str(value)
values.append(value)
- file.write(','.join(values) + '\n')
- file.close()
+ f.write(','.join(values) + '\n')
+ f.close()
def version(self):
- return '0.2'
+ return '.'.join(map(str, version))
## Exception handling ##
def handleException(self, excInfo):
- """
- Invoked by self when an exception occurs in the target
- script. <code>excInfo</code> is a sys.exc_info()-style
- tuple of information about the exception.
- """
+ """Handle an exception in the target script.
- self._scriptEndTime = time() # Note the duration of the script and time of the exception
+ Invoked by self when an exception occurs in the target script.
+ <code>excInfo</code> is a sys.exc_info()-style tuple of information
+ about the exception.
+
+ """
+ # Note the duration of the script and time of the exception
+ self._scriptEndTime = time()
self.logExceptionToConsole()
self.reset()
print self.htmlErrorPage(showDebugInfo=self.setting('ShowDebugInfoOnErrors'))
@@ -268,11 +270,12 @@
self.emailException(fullErrorMsg)
def logExceptionToConsole(self, stderr=sys.stderr):
- """
- Logs the time, script name and traceback to the
- console (typically stderr). This usually results in
- the information appearing in the web server's error
- log. Used by handleException().
+ """Log an exception in the target script.
+
+ Logs the time, script name and traceback to the console
+ (typically stderr). This usually results in the information
+ appearing in the web server's error log. Used by handleException().
+
"""
# stderr logging
stderr.write('[%s] [error] CGI Wrapper: Error while executing script %s\n' % (
@@ -280,33 +283,31 @@
traceback.print_exc(file=stderr)
def reset(self):
- """
- Used by handleException() to clear out the current CGI
- output results in preparation of delivering an HTML
- error message page. Currently resets headers and
- deletes cookies, if present.
+ """Reset CGI output.
+
+ Used by handleException() to clear out the current CGI output results
+ in preparation of delivering an HTML error message page.
+ Currently resets headers and deletes cookies, if present.
"""
# Set headers to basic text/html. We don't want stray headers from a script that failed.
- headers = {'Content-Type': 'text/html'}
-
+ self._headers = self.makeHeaders()
# Get rid of cookies, too
if self._namespace.has_key('cookies'):
del self._namespace['cookies']
def htmlErrorPage(self, showDebugInfo=1):
+ """Return an HTML page explaining that there is an error.
+
+ There could be more options in the future so using named arguments
+ (e.g., 'showDebugInfo=1') is recommended. Invoked by handleException().
+
"""
- Returns an HTML page explaining that there is an
- error. There could be more options in the future so
- using named arguments (e.g., 'showDebugInfo=1') is
- recommended. Invoked by handleException().
- """
- html = ['''
+ html = ['''%s
<html>
<title>Error</title>
- <body fgcolor=black bgcolor=white>
-%s
-<p>%s</p>
-''' % (htTitle('Error'), self.setting('UserErrorMessage'))]
+ <body text="black" bgcolor="white">
+%s<p>%s</p>
+''' % (docType(), htTitle('Error'), self.setting('UserErrorMessage'))]
if self.setting('ShowDebugInfoOnErrors'):
html.append(self.htmlDebugInfo())
@@ -315,79 +316,96 @@
return ''.join(html)
def htmlDebugInfo(self):
- """
- Return HTML-formatted debugging information about the
- current exception. Used by handleException().
+ """Return an HTML page with debugging info on the current exception.
+
+ Used by handleException().
+
"""
html = ['''
-%s
-<p><i>%s</i></p>
+%s<p><i>%s</i></p>
''' % (htTitle('Traceback'), self._scriptPathname)]
-
html.append(HTMLForException())
-
html.extend([
htTitle('Misc Info'),
htDictionary({
- 'time': asctime(localtime(self._scriptEndTime)),
- 'filename': self._scriptPathname,
- 'os.getcwd()': os.getcwd(),
- 'sys.path': sys.path
+ 'time': asctime(localtime(self._scriptEndTime)),
+ 'filename': self._scriptPathname,
+ 'os.getcwd()': os.getcwd(),
+ 'sys.path': sys.path
}),
- htTitle('Fields'), htDictionary(self._fields),
- htTitle('Headers'), htDictionary(self._headers),
- htTitle('Environment'), htDictionary(self._environ, {'PATH': ';'}),
- htTitle('Ids'), htTable(osIdTable(), ['name', 'value'])])
-
+ htTitle('Fields'), htDictionary(self._fields),
+ htTitle('Headers'), htDictionary(self._headers),
+ htTitle('Environment'), htDictionary(self._environ, {'PATH': ';'}),
+ htTitle('Ids'), htTable(osIdTable(), ['name', 'value'])])
return ''.join(html)
def saveHTMLErrorPage(self, html):
+ """Save the given HTML error page for later viewing by the developer.
+
+ Returns the filename used. Invoked by handleException().
+
"""
- Saves the given HTML error page for later viewing by
- the developer, and returns the filename used. Invoked
- by handleException().
- """
- filename = os.path.join(self.setting('ErrorMessagesDir'), self.htmlErrorPageFilename())
- f = open(filename, 'w')
- f.write(html)
- f.close()
- return filename
+ dir = self.setting('ErrorMessagesDir')
+ if not os.path.exists(dir):
+ os.makedirs(dir)
+ filename = os.path.join(dir, self.htmlErrorPageFilename())
+ try:
+ f = open(filename, 'w')
+ try:
+ f.write(html)
+ finally:
+ f.close()
+ except IOError:
+ sys.stderr.write('[%s] [error] CGI Wrapper: Cannot save error page (%s)\n'
+ % (asctime(localtime(time())), filename))
+ else:
+ return filename
def htmlErrorPageFilename(self):
- """Construct a filename for an HTML error page, not including the 'ErrorMessagesDir' setting."""
- return 'Error-%s-%s-%d.html' % (
- os.path.split(self._scriptPathname)[1],
- '-'.join(map(lambda x: '%02d' % x, localtime(self._scriptEndTime)[:6])),
- random.randint(10000, 99999))
- # @@ 2000-04-21 ce: Using the timestamp & a random number is a poor technique for filename uniqueness, but this works for now
+ """Construct a filename for an HTML error page.
+
+ This filename does not include the 'ErrorMessagesDir' setting.
- def logExceptionToDisk(self, errorMsgFilename='', excInfo=None):
"""
- Writes a tuple containing (date-time, filename,
- pathname, exception-name, exception-data,error report
- filename) to the errors file (typically 'Errors.csv')
- in CSV format. Invoked by handleException().
+ # Note: Using the timestamp and a random number is a poor technique
+ # for filename uniqueness, but it is fast and good enough in practice.
+ return 'Error-%s-%s-%06d.html' % (os.path.split(self._scriptPathname)[1],
+ '-'.join(map(lambda x: '%02d' % x, localtime(self._scriptEndTime)[:6])),
+ randint(0, 999999))
+
+ def logExceptionToDisk(self, errorMsgFilename=None, excInfo=None):
+ """Write exception info to the log file.
+
+ Writes a tuple containing (date-time, filename, pathname,
+ exception-name, exception-data, error report filename)
+ to the errors file (typically 'Errors.csv') in CSV format.
+ Invoked by handleException().
+
"""
if not excInfo:
excInfo = sys.exc_info()
- logline = (
- asctime(localtime(self._scriptEndTime)),
- os.path.split(self._scriptPathname)[1],
- self._scriptPathname,
- str(excInfo[0]),
- str(excInfo[1]),
- errorMsgFilename)
+ logline = (asctime(localtime(self._scriptEndTime)),
+ os.path.split(self._scriptPathname)[1], self._scriptPathname,
+ excInfo[0].__name__, str(excInfo[1]), errorMsgFilename or '')
+ def fixElement(element):
+ element = str(element)
+ if element.find(',') >= 0 or element.find('"') >= 0:
+ element = element.replace('"', '""')
+ element = '"%s"' % element
+ return element
+ logline = map(fixElement, logline)
filename = self.setting('ErrorLogFilename')
if os.path.exists(filename):
f = open(filename, 'a')
else:
f = open(filename, 'w')
- f.write('time,filename,pathname,exception name,exception data,error report filename\n')
- f.write(','.join(logline))
- f.write('\n')
+ f.write('time,filename,pathname,exception name,'
+ 'exception data,error report filename\n')
+ f.write(','.join(logline) + '\n')
f.close()
def emailException(self, html, excInfo=None):
+ """Email an exception."""
# Construct the message
if not excInfo:
excInfo = sys.exc_info()
@@ -399,10 +417,6 @@
msg.append('\n')
msg.append(html)
msg = ''.join(msg)
-
- # dbg code, in case you're having problems with your e-mail
- # open('error-email-msg.text', 'w').write(msg)
-
# Send the message
import smtplib
server = smtplib.SMTP(self.setting('ErrorEmailServer'))
@@ -414,6 +428,7 @@
## Serve ##
def serve(self, environ=os.environ):
+ """Serve a request."""
# Record the time
if globals().has_key('isMain'):
self._serverStartTime = serverStartTime
@@ -433,13 +448,11 @@
self._scriptPathname = self.scriptPathname()
self._scriptName = os.path.split(self._scriptPathname)[1]
- # @@ 2000-04-16 ce: Does _namespace need to be an ivar?
self._namespace = {
'headers': self._headers,
'fields': self._fields,
'environ': self._environ,
'wrapper': self,
- # 'WebUtils': WebUtils, # @@ 2000-05-01 ce: Resolve.
}
info = self._namespace.copy()
@@ -472,7 +485,8 @@
for name in self.setting('ClassNames'):
if name == '':
name = os.path.splitext(self._scriptName)[0]
- if self._namespace.has_key(name): # our hook for class-oriented scripts
+ if self._namespace.has_key(name):
+ # our hook for class-oriented scripts
print self._namespace[name](info).html()
break
else:
@@ -519,10 +533,13 @@
if self.setting('LogScripts'):
self.writeScriptLog()
-
def deliver(self):
- """Deliver the HTML, whether it came from the script being served, or from our own error reporting."""
+ """Deliver the HTML.
+
+ This is used for the output that came from the script being served,
+ or from our own error reporting.
+ """
# Compile the headers & cookies
headers = StringIO()
for header, value in self._headers.items():
@@ -543,75 +560,89 @@
self._realStdout.write(stdoutOut)
-# Some misc functions
+## Misc functions ##
+
+def docType():
+ """Return a standard HTML document type"""
+ return ('<!DOCTYPE HTML PUBLIC'
+ ' "-//W3C//DTD HTML 4.01 Transitional//EN"'
+ ' "http://www.w3.org/TR/html4/loose.dtd">')
+
def htTitle(name):
- return '''
-<p> </p>
-<table border="0" cellpadding="4" cellspacing="0" bgcolor="#A00000">
-<tr><td>
-<font face="Tahoma, Arial, Helvetica" color=white><b>%s</b></font>
-</td></tr></table>
-''' % name
+ """Return an HTML section title."""
+ return ('<h2 style="color:white;background-color:#993333;'
+ 'font-size:12pt;padding:1pt;font-weight:bold;'
+ 'font-family:Tahoma,Verdana,Arial,Helvetica,sans-serif"'
+ ' align="center">%s</h2>\n' % name)
def htDictionary(dict, addSpace=None):
- """Returns an HTML string with a <table> where each row is a key-value pair."""
+ """Returns an HTML table where each row is a key-value pair."""
+ if not dict:
+ return '\n'
keys = dict.keys()
keys.sort()
- html = ['<table width="100%" border="0" cellpadding="2" cellspacing="2" bgcolor="#F0F0F0">']
+ html = ['<table border="0" cellpadding="2" cellspacing="2">']
for key in keys:
value = dict[key]
if addSpace is not None and addSpace.has_key(key):
target = addSpace[key]
value = (target + ' ').join(value.split(target))
- html.append('<tr><td>%s</td><td>%s </td></tr>\n' % (key, value))
+ html.append('<tr><td bgcolor="#BBBBBB">%s</td>'
+ '<td bgcolor="#EEEEEE">%s </td></tr>\n' % (key, value))
html.append('</table>')
return '\n'.join(html)
-def osIdTable():
- """
- Returns a list of dictionaries contained id information such
- as uid, gid, etc., all obtained from the os module. Dictionary
- keys are 'name' and 'value'.
- """
- funcs = ['getegid', 'geteuid', 'getgid', 'getpgrp', 'getpid', 'getppid', 'getuid']
- table = []
- for funcName in funcs:
- if hasattr(os, funcName):
- value = getattr(os, funcName)()
- table.append({'name': funcName, 'value': value})
- return table
-
def htTable(listOfDicts, keys=None):
- """
+ """Return an HTML table for a list of dictionaries.
+
The listOfDicts parameter is expected to be a list of
- dictionaries whose keys are always the same. This function
- returns an HTML string with the contents of the table. If
- keys is None, the headings are taken from the first row in
- alphabetical order. Returns an empty string if listOfDicts is
- none or empty.
+ dictionaries whose keys are always the same. This function
+ returns an HTML string with the contents of the table.
+ If keys is None, the headings are taken from the first row in
+ alphabetical order.
+
+ Returns an empty string if listOfDicts is none or empty.
Deficiencies: There's no way to influence the formatting or to
- use column titles that are different than the keys.
- """
+ use column titles that are different from the keys.
+ """
if not listOfDicts:
return ''
if keys is None:
keys = listOfDicts[0].keys()
keys.sort()
- html = ['<table border="0" cellpadding="2" cellspacing="2" bgcolor="#F0F0F0">']
+ html = ['<table border="0" cellpadding="2" cellspacing="2">']
html.append('<tr>')
for key in keys:
- html.append('<th>%s</th>' % key)
+ html.append('<th bgcolor="#BBBBBB">%s</th>' % key)
html.append('</tr>')
for row in listOfDicts:
html.append('<tr>')
for key in keys:
- html.append('<td>%s</td>' % row[key])
+ html.append('<td bgcolor="#EEEEEE">%s</td>' % row[key])
html.append('</tr>')
html.append('</table>')
return '\n'.join(html)
+def osIdTable():
+ """Get all OS id information.
+
+ Returns a list of dictionaries containing id information such
+ as uid, gid, etc., all obtained from the os module.
+
+ Dictionary keys are 'name' and 'value'.
+
+ """
+ funcs = ['getegid', 'geteuid', 'getgid', 'getpgrp',
+ 'getpid', 'getppid', 'getuid']
+ table = []
+ for funcName in funcs:
+ if hasattr(os, funcName):
+ value = getattr(os, funcName)()
+ table.append({'name': funcName, 'value': value})
+ return table
+
def main():
stdout = sys.stdout
@@ -623,21 +654,23 @@
# uncaught exceptions from target scripts. However, we should also
# catch exceptions here that might come from the wrapper, including
# ones generated while it's handling exceptions.
- import traceback
- sys.stderr.write('[%s] [error] CGI Wrapper: Error while executing script (unknown)\n' % (
- asctime(localtime(time()))))
- sys.stderr.write('Error while executing script\n')
+ sys.stderr.write('[%s] [error] CGI Wrapper: Error while executing script (unknown)\n'
+ % asctime(localtime(time())))
traceback.print_exc(file=sys.stderr)
- output = traceback.format_exception(*sys.exc_info())
- output = ''.join(output)
- output = output.replace('&', '&').replace('<', '<').replace('>', '>')
- stdout.write('''Content-type: text/html
+ if sys.exc_info()[0] != SystemExit:
+ output = traceback.format_exception(*sys.exc_info())
+ output = ''.join(output)
+ output = output.replace('&', '&').replace('<', '<').replace('>', '>')
+ stdout.write('''Content-type: text/html
-<html><body>
-<p>ERROR</p>
+%s
+<html>
+<head><title>Error</title>
+<body><h2>ERROR</h2>
<pre>%s</pre>
-</body></html>
-''' % output)
+</body>
+</html>
+''' % (docType(), output))
if __name__ == '__main__':
Modified: Webware/trunk/CGIWrapper/Docs/RelNotes-X.Y.phtml
==============================================================================
--- Webware/trunk/CGIWrapper/Docs/RelNotes-X.Y.phtml (original)
+++ Webware/trunk/CGIWrapper/Docs/RelNotes-X.Y.phtml Sun Dec 9 05:24:09 2007
@@ -19,17 +19,24 @@
<a name="Improvements"></a><h2>Improvements and Refinements</h2>
<ul>
- <li>...</li>
+ <li>Output is now nicer and fully HTML compliant.</li>
+ <li>A couple of minor improvements and code clean-up.</li>
</ul>
<a name="Security"></a><h2>Security</h2>
<ul>
- <li>...</li>
+ <li>Access to the admin scripts is now restricted to the local host.
+ A new setting <code>AdminRemoteAddr</code> allows adding
+ more remote addresses for administration.</li>
+ <li>The view scripts do not allow changing the path any more.</li>
</ul>
-<a name="MinorChanges"></a><h2>Minor API Changes</h2>
+<a name="MinorChanges"></a><h2>Minor Changes</h2>
<ul>
- <li>...</li>
+ <li>The default config file has been renamed to
+ <span class="filename">CGIWrapper.config</span>.</li>
+ <li>The default <code>ScriptsHomeDir</code> has been changed to
+ <span class="filename">Examples</span>.</li>
</ul>
<a name="Bugfixes"></a><h2>Bugfixes</h2>
Modified: Webware/trunk/CGIWrapper/Docs/SampleAdmin.html
==============================================================================
--- Webware/trunk/CGIWrapper/Docs/SampleAdmin.html (original)
+++ Webware/trunk/CGIWrapper/Docs/SampleAdmin.html Sun Dec 9 05:24:09 2007
@@ -1,30 +1,33 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
- <head>
- <title>Admin</title>
- </head>
- <body color=black bgcolor=white><table align=center><tr><td>
-<table align=center bgcolor=darkblue cellpadding=5 cellspacing=0 width=100%>
- <tr><td align=center>
- <font face="Tahoma, Arial, Helvetica" color=white><b>
- CGI Wrapper
- <br><font size=+2>Admin</font>
- </b></font>
- </td></tr>
- </table><p>
+ <head>
+ <title>Admin</title>
+ </head>
+ <body text="black" bgcolor="#555555">
+ <table align="center" bgcolor="white"><tr><td>
- <table align=center cellspacing=0 cellpadding=0 borde=0>
- <tr> <td><b>Version:</b></td> <td>0.2</td> </tr>
- <tr> <td><b>Local time:</b></td> <td>Mon Apr 24 20:58:11 2000</td> </tr>
- <tr> <td><b>Global time:</b></td> <td>Tue Apr 25 00:58:11 2000</td> </tr>
+ <table align="center" bgcolor="#202080" cellpadding="5" cellspacing="0" width="100%">
+ <tr><td align="center" style="color:white;font-weight:bold;font-family:Tahoma,Verdana,Arial,Helvetica,sans-serif">
+ <div style="font-size:14pt">CGI Wrapper</div>
+ <div style="font-size:16pt">Admin</div>
+ </td></tr>
</table>
-
-<p><table align=center border=0 cellspacing=2 cellpadding=2 bgcolor=#FFFFDD>
-<tr bgcolor=black><td align=center><font face="Arial, Helvetica" color=white><b>Menu</b></font></td></tr>
-<tr><td> <a href="_dumpCSV?filename=Scripts.csv">Script log contents</a> </td></tr>
-<tr><td> <a href="_dumpErrors?filename=Errors.csv">Error log contents</a> </td></tr>
-<tr><td> <a href="_showConfig">Show config</a> </td></tr>
-</table>
+ <table align="center" cellspacing="2" cellpadding="2" border="0">
+ <tr><th>Version:</th><td>0.2</td></tr>
+ <tr><th>Local time:</th><td>Mon Apr 24 20:58:11 2000</td></tr>
+ <tr><th>Global time:</th><td>Tue Apr 25 00:58:11 2000</td></tr>
+ </table>
+
+ <div style="font-size:12pt;font-family:Arial,Helvetica,sans-serif">
+ <table align="center" border="0" cellspacing="2" cellpadding="2" bgcolor="#E8E8F0">
+ <tr bgcolor="#101040"><th align="center" style="color:white">Menu</th></tr>
+ <tr><td>
+ <tr><td align="center"><a href="_dumpCSV?filename=Scripts.csv">Script log contents</a></td></tr>
+ <tr><td align="center"><a href="_dumpErrors?filename=Errors.csv">Error log contents</a></td></tr>
+ <tr><td align="center"><a href="_showConfig">Show config</a></td></tr>
+ </table>
+ </div>
<!--
begin-parse
{
@@ -34,5 +37,8 @@
}
end-parse
-->
-<p><br><hr></table></body></html>
-
+ <hr>
+ <div align="center" style="font-size:small">Webware for Python</div>
+ </td></tr></table>
+ </body>
+</html>
Modified: Webware/trunk/CGIWrapper/Docs/SampleError.html
==============================================================================
--- Webware/trunk/CGIWrapper/Docs/SampleError.html (original)
+++ Webware/trunk/CGIWrapper/Docs/SampleError.html Sun Dec 9 05:24:09 2007
@@ -1,78 +1,75 @@
-
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
- <title>Error</title>
- <body fgcolor=black bgcolor=white>
+<title>Error</title>
+<body text="black" bgcolor="white">
+
+<h2 style="color:white;background-color:#933;font-size:12pt;padding:1pt;font-weight:bold;font-family:Tahoma,Verdana,Arial,Helvetica,sans-serif" align="center">Error</h2>
+<p> The site is having technical difficulties with this page. An error has been logged, and the problem will be fixed as soon as possible. Sorry!</p>
-<p> <br> <table border=0 cellpadding=4 cellspacing=0 bgcolor=#A00000> <tr> <td>
- <font face="Tahoma, Arial, Helvetica" color=white> <b> Error </b> </font>
-</td> </tr> </table>
-<p> The site is having technical difficulties with this page. An error has been logged, and the problem will be fixed as soon as possible. Sorry!
-
-<p> <br> <table border=0 cellpadding=4 cellspacing=0 bgcolor=#A00000> <tr> <td>
- <font face="Tahoma, Arial, Helvetica" color=white> <b> Traceback </b> </font>
-</td> </tr> </table>
+<h2 style="color:white;background-color:#933;font-size:12pt;padding:1pt;font-weight:bold;font-family:Tahoma,Verdana,Arial,Helvetica,sans-serif" align="center">Traceback</h2>
<p> <i>/home/echuck/public_html/pycgi/Scripts/Error.py</i>
-<table bgcolor=#F0F0F0 width=100% cellpadding=4><tr><td>
-<pre><font color=#000000>Traceback (innermost last):
-<font color=#0000AA> File "CGIWrapper.py", line 338, in go</font>
-<font color=#FF0000> execfile(self._scriptPathname, self._namespace)</font>
-<font color=#0000AA> File "/home/echuck/public_html/pycgi/Scripts/Error.py", line 7, in ?</font>
-<font color=#FF0000> import UnknownModuleName</font>
-ImportError: No module named UnknownModuleName</font></pre></td></tr></table>
-
-<p> <br> <table border=0 cellpadding=4 cellspacing=0 bgcolor=#A00000> <tr> <td>
- <font face="Tahoma, Arial, Helvetica" color=white> <b> Misc Info </b> </font>
-</td> </tr> </table><table width=100% border=0 cellpadding=2 cellspacing=2 bgcolor=#F0F0F0><tr> <td> filename </td> <td> /home/echuck/public_html/pycgi/Scripts/Error.py </td> </tr>
-<tr> <td> os.getcwd() </td> <td> /home/echuck/Projects/Webware/CGIWrapper </td> </tr>
-<tr> <td> sys.path </td> <td> ['', '/usr/lib/python1.5/', '/usr/lib/python1.5/plat-linux-i386', '/usr/lib/python1.5/lib-tk', '/usr/lib/python1.5/lib-dynload', '/usr/lib/python1.5/site-packages', '..'] </td> </tr>
-<tr> <td> time </td> <td> Fri Apr 21 16:35:25 2000 </td> </tr>
+<table width="100%" cellpadding="2" cellspacing="2" bgcolor="#EEE"><tr><td>
+<pre><span style="color:#000">Traceback (innermost last):
+<span style="color:#009"> File "CGIWrapper.py", line 338, in go</span>
+<span style="color:#900"> execfile(self._scriptPathname, self._namespace)</span>
+<span style="color:#009"> File "/home/echuck/public_html/pycgi/Scripts/Error.py", line 7, in ?</span>
+<span style="color:#900"> import UnknownModuleName</span>
+ImportError: No module named UnknownModuleName</span></pre></td></tr></table>
+
+<h2 style="color:white;background-color:#933;font-size:12pt;padding:1pt;font-weight:bold;font-family:Tahoma,Verdana,Arial,Helvetica,sans-serif" align="center">Misc Info</h2>
+<table border="0" cellpadding="2" cellspacing="2"><tr><td bgcolor="#BBB"> filename </td><td bgcolor="#EEE"> /home/echuck/public_html/pycgi/Scripts/Error.py </td></tr>
+<tr><td bgcolor="#BBB"> os.getcwd() </td><td bgcolor="#EEE"> /home/echuck/Projects/Webware/CGIWrapper </td></tr>
+<tr><td bgcolor="#BBB"> sys.path </td><td bgcolor="#EEE"> ['', '/usr/lib/python1.5/', '/usr/lib/python1.5/plat-linux-i386', '/usr/lib/python1.5/lib-tk', '/usr/lib/python1.5/lib-dynload', '/usr/lib/python1.5/site-packages', '..'] </td></tr>
+<tr><td bgcolor="#BBB"> time </td><td bgcolor="#EEE"> Fri Apr 21 16:35:25 2000 </td></tr>
</table>
-<p> <br> <table border=0 cellpadding=4 cellspacing=0 bgcolor=#A00000> <tr> <td>
- <font face="Tahoma, Arial, Helvetica" color=white> <b> Fields </b> </font>
-</td> </tr> </table><table width=100% border=0 cellpadding=2 cellspacing=2 bgcolor=#F0F0F0></table>
-<p> <br> <table border=0 cellpadding=4 cellspacing=0 bgcolor=#A00000> <tr> <td>
- <font face="Tahoma, Arial, Helvetica" color=white> <b> Headers </b> </font>
-</td> </tr> </table><table width=100% border=0 cellpadding=2 cellspacing=2 bgcolor=#F0F0F0><tr> <td> Content-type </td> <td> text/html </td> </tr>
+
+<h2 style="color:white;background-color:#933;font-size:12pt;padding:1pt;font-weight:bold;font-family:Tahoma,Verdana,Arial,Helvetica,sans-serif" align="center">Fields</h2>
+
+<h2 style="color:white;background-color:#933;font-size:12pt;padding:1pt;font-weight:bold;font-family:Tahoma,Verdana,Arial,Helvetica,sans-serif" align="center">Headers</h2>
+<table border="0" cellpadding="2" cellspacing="2"><tr><td bgcolor="#BBB"> Content-type </td><td bgcolor="#EEE"> text/html </td></tr>
</table>
-<p> <br> <table border=0 cellpadding=4 cellspacing=0 bgcolor=#A00000> <tr> <td>
- <font face="Tahoma, Arial, Helvetica" color=white> <b> Environment </b> </font>
-</td> </tr> </table><table width=100% border=0 cellpadding=2 cellspacing=2 bgcolor=#F0F0F0><tr> <td> DOCUMENT_ROOT </td> <td> /home/httpd/html </td> </tr>
-<tr> <td> GATEWAY_INTERFACE </td> <td> CGI/1.1 </td> </tr>
-<tr> <td> HTTP_ACCEPT </td> <td> image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */* </td> </tr>
-<tr> <td> HTTP_ACCEPT_CHARSET </td> <td> iso-8859-1,*,utf-8 </td> </tr>
-<tr> <td> HTTP_ACCEPT_ENCODING </td> <td> gzip </td> </tr>
-<tr> <td> HTTP_ACCEPT_LANGUAGE </td> <td> en </td> </tr>
-<tr> <td> HTTP_CONNECTION </td> <td> Keep-Alive </td> </tr>
-<tr> <td> HTTP_HOST </td> <td> localhost </td> </tr>
-<tr> <td> HTTP_PRAGMA </td> <td> no-cache </td> </tr>
-<tr> <td> HTTP_REFERER </td> <td> http://localhost/~echuck/pycgi/server.cgi/Directory </td> </tr>
-<tr> <td> HTTP_USER_AGENT </td> <td> Mozilla/4.7 [en] (X11; I; Linux 2.2.14-15mdk i686) </td> </tr>
-<tr> <td> PATH </td> <td> /usr/local/bin:/usr/bin:/bin </td> </tr>
-<tr> <td> PATH_INFO </td> <td> /Error </td> </tr>
-<tr> <td> PATH_TRANSLATED </td> <td> /home/httpd/html/Error </td> </tr>
-<tr> <td> QUERY_STRING </td> <td> </td> </tr>
-<tr> <td> REMOTE_ADDR </td> <td> 127.0.0.1 </td> </tr>
-<tr> <td> REMOTE_PORT </td> <td> 1081 </td> </tr>
-<tr> <td> REQUEST_METHOD </td> <td> GET </td> </tr>
-<tr> <td> REQUEST_URI </td> <td> /~echuck/pycgi/server.cgi/Error </td> </tr>
-<tr> <td> SCRIPT_FILENAME </td> <td> /home/echuck/public_html/pycgi/server.cgi </td> </tr>
-<tr> <td> SCRIPT_NAME </td> <td> /~echuck/pycgi/server.cgi </td> </tr>
-<tr> <td> SERVER_ADDR </td> <td> 127.0.0.1 </td> </tr>
-<tr> <td> SERVER_ADMIN </td> <td> root@... </td> </tr>
-<tr> <td> SERVER_NAME </td> <td> localhost.localdomain </td> </tr>
-<tr> <td> SERVER_PORT </td> <td> 80 </td> </tr>
-<tr> <td> SERVER_PROTOCOL </td> <td> HTTP/1.0 </td> </tr>
-<tr> <td> SERVER_SOFTWARE </td> <td> Apache/1.3.9 (NetRevolution Advanced Extranet Server/Linux-Mandrake) PHP/3.0.13 mod_perl/1.21 </td> </tr>
+
+<h2 style="color:white;background-color:#933;font-size:12pt;padding:1pt;font-weight:bold;font-family:Tahoma,Verdana,Arial,Helvetica,sans-serif" align="center">Environment</h2>
+<table border="0" cellpadding="2" cellspacing="2">
+<tr><td bgcolor="#BBB"> DOCUMENT_ROOT </td><td bgcolor="#EEE"> /home/httpd/html </td></tr>
+<tr><td bgcolor="#BBB"> GATEWAY_INTERFACE </td><td bgcolor="#EEE"> CGI/1.1 </td></tr>
+<tr><td bgcolor="#BBB"> HTTP_ACCEPT </td><td bgcolor="#EEE"> image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */* </td></tr>
+<tr><td bgcolor="#BBB"> HTTP_ACCEPT_CHARSET </td><td bgcolor="#EEE"> iso-8859-1,*,utf-8 </td></tr>
+<tr><td bgcolor="#BBB"> HTTP_ACCEPT_ENCODING </td><td bgcolor="#EEE"> gzip </td></tr>
+<tr><td bgcolor="#BBB"> HTTP_ACCEPT_LANGUAGE </td><td bgcolor="#EEE"> en </td></tr>
+<tr><td bgcolor="#BBB"> HTTP_CONNECTION </td><td bgcolor="#EEE"> Keep-Alive </td></tr>
+<tr><td bgcolor="#BBB"> HTTP_HOST </td><td bgcolor="#EEE"> localhost </td></tr>
+<tr><td bgcolor="#BBB"> HTTP_PRAGMA </td><td bgcolor="#EEE"> no-cache </td></tr>
+<tr><td bgcolor="#BBB"> HTTP_REFERER </td><td bgcolor="#EEE"> http://localhost/~echuck/pycgi/server.cgi/Directory </td></tr>
+<tr><td bgcolor="#BBB"> HTTP_USER_AGENT </td><td bgcolor="#EEE"> Mozilla/4.7 [en] (X11; I; Linux 2.2.14-15mdk i686) </td></tr>
+<tr><td bgcolor="#BBB"> PATH </td><td bgcolor="#EEE"> /usr/local/bin:/usr/bin:/bin </td></tr>
+<tr><td bgcolor="#BBB"> PATH_INFO </td><td bgcolor="#EEE"> /Error </td></tr>
+<tr><td bgcolor="#BBB"> PATH_TRANSLATED </td><td bgcolor="#EEE"> /home/httpd/html/Error </td></tr>
+<tr><td bgcolor="#BBB"> QUERY_STRING </td><td bgcolor="#EEE"> </td></tr>
+<tr><td bgcolor="#BBB"> REMOTE_ADDR </td><td bgcolor="#EEE"> 127.0.0.1 </td></tr>
+<tr><td bgcolor="#BBB"> REMOTE_PORT </td><td bgcolor="#EEE"> 1081 </td></tr>
+<tr><td bgcolor="#BBB"> REQUEST_METHOD </td><td bgcolor="#EEE"> GET </td></tr>
+<tr><td bgcolor="#BBB"> REQUEST_URI </td><td bgcolor="#EEE"> /~echuck/pycgi/server.cgi/Error </td></tr>
+<tr><td bgcolor="#BBB"> SCRIPT_FILENAME </td><td bgcolor="#EEE"> /home/echuck/public_html/pycgi/server.cgi </td></tr>
+<tr><td bgcolor="#BBB"> SCRIPT_NAME </td><td bgcolor="#EEE"> /~echuck/pycgi/server.cgi </td></tr>
+<tr><td bgcolor="#BBB"> SERVER_ADDR </td><td bgcolor="#EEE"> 127.0.0.1 </td></tr>
+<tr><td bgcolor="#BBB"> SERVER_ADMIN </td><td bgcolor="#EEE"> root@... </td></tr>
+<tr><td bgcolor="#BBB"> SERVER_NAME </td><td bgcolor="#EEE"> localhost.localdomain </td></tr>
+<tr><td bgcolor="#BBB"> SERVER_PORT </td><td bgcolor="#EEE"> 80 </td></tr>
+<tr><td bgcolor="#BBB"> SERVER_PROTOCOL </td><td bgcolor="#EEE"> HTTP/1.0 </td></tr>
+<tr><td bgcolor="#BBB"> SERVER_SOFTWARE </td><td bgcolor="#EEE"> Apache/1.3.9 (NetRevolution Advanced Extranet Server/Linux-Mandrake) PHP/3.0.13 mod_perl/1.21 </td></tr>
+</table>
+
+<h2 style="color:white;background-color:#933;font-size:12pt;padding:1pt;font-weight:bold;font-family:Tahoma,Verdana,Arial,Helvetica,sans-serif" align="center">Ids</h2>
+<table border=0 cellpadding=2 cellspacing=2>
+<tr><td bgcolor="#BBB"><b>name</b></td><td bgcolor="#EEE"><b>value</b></td></tr>
+<tr><td bgcolor="#BBB">egid</td><td bgcolor="#EEE">503</td></tr>
+<tr><td bgcolor="#BBB">euid</td><td bgcolor="#EEE">501</td></tr>
+<tr><td bgcolor="#BBB">gid</td><td bgcolor="#EEE">503</td></tr>
+<tr><td bgcolor="#BBB">pgrp</td><td bgcolor="#EEE">556</td></tr>
+<tr><td bgcolor="#BBB">pid</td><td bgcolor="#EEE">933</td></tr>
+<tr><td bgcolor="#BBB">ppid</td><td bgcolor="#EEE">879</td></tr>
+<tr><td bgcolor="#BBB">uid</td><td bgcolor="#EEE">501</td></tr>
</table>
-<p> <br> <table border=0 cellpadding=4 cellspacing=0 bgcolor=#A00000> <tr> <td>
- <font face="Tahoma, Arial, Helvetica" color=white> <b> Ids </b> </font>
-</td> </tr> </table><table border=0 cellpadding=2 cellspacing=2 bgcolor=#F0F0F0>
-<tr><td><b>name</b></td><td><b>value</b></td></tr>
-<tr><td>egid</td><td>503</td></tr>
-<tr><td>euid</td><td>501</td></tr>
-<tr><td>gid</td><td>503</td></tr>
-<tr><td>pgrp</td><td>556</td></tr>
-<tr><td>pid</td><td>933</td></tr>
-<tr><td>ppid</td><td>879</td></tr>
-<tr><td>uid</td><td>501</td></tr>
-</table></body></html>
+
+</body></html>
Modified: Webware/trunk/CGIWrapper/Docs/UsersGuide.phtml
==============================================================================
--- Webware/trunk/CGIWrapper/Docs/UsersGuide.phtml (original)
+++ Webware/trunk/CGIWrapper/Docs/UsersGuide.phtml Sun Dec 9 05:24:09 2007
@@ -24,7 +24,7 @@
<p>The wrapper provides the following benefits:</p>
<ul>
- <li>Sets up global variables <em>headers</em>, <em>fields</em>, <em>env</em> and <em>wrapper</em> for use by the target script.</li>
+ <li>Sets up global variables <em>headers</em>, <em>fields</em>, <em>env</em>, <em>wrapper</em> and <em>WebUtils</em> for use by the target script.</li>
<li>Catches exceptions that the target script doesn't in order to provide a meaningful message to the web page reader and useful debugging information to the developer.</li>
<li>Logs the date, time, duration and name of the target script for usage statistics and performance monitoring.</li>
<li>Simplifies URLs by leaving out the extension and possibly the location of the script. This also hides the nature of the implementation of the page from the browser of your site.</li>
@@ -54,7 +54,7 @@
<tr>
<td><code>environ</code> </td>
<td>dictionary </td>
- <td>This dictionary represents the environment variables passed to the CGI scripts. Scripts should use this rather than <code>os.environ</code> since future versions of CGI Wrapper could be tightly integrated into webservers, thereby changing the nature of how environment variables get passed around (e.g., no longer through the OS). Also, note that the environment may seem a little non-standard to the target CGI script since the web server is setting it up to run the CGI Wrapper instead. In most CGI scripts (that execute under the wrapper), the environment is not even needed. </td>
+ <td>This dictionary represents the environment variables passed to the CGI scripts. Scripts should use this rather than <code>os.environ</code> since future versions of CGI Wrapper could be tightly integrated into web servers, thereby changing the nature of how environment variables get passed around (e.g., no longer through the OS). Also, note that the environment may seem a little non-standard to the target CGI script since the web server is setting it up to run the CGI Wrapper instead. In most CGI scripts (that execute under the wrapper), the environment is not even needed. </td>
</tr>
<tr>
<td><code>wrapper</code> </td>
@@ -94,9 +94,9 @@
<dl>
<dt><b>ScriptsHomeDir</b>
- <code> = '/Scripts'</code></dt>
+ <code> = 'Examples'</code></dt>
<dd>
-This is where the wrapper always looks for the CGI scripts. There this location would <b>not</b> appear in URLs. The path can be relative to the CGI Wrapper's location, or an absolute path.
+This is where the wrapper always looks for the CGI scripts. This location would <b>not</b> appear in URLs. The path can be relative to the CGI Wrapper's location, or an absolute path. You should change this to your own <code>Scripts</code> directory instead of putting your scripts in the <code>Examples</code> directory.
</dd>
</dl>
@@ -147,7 +147,7 @@
'environ.REQUEST_METHOD', 'environ.REQUEST_URI',
'responseSize', 'scriptName', 'serverStartTimeStamp',
'serverDuration', 'scriptDuration', 'errorOccurred']</code></p>
-Specifies the columns that will be stored in the script log. Each column is the name of an attribute of CGI Wrapper. The <b>Introspect</b> CGI example gives a list of all CGI Wrapper attributes. Note that attributes which are dictionaries, UserDicts or subclasses of MiddleKit's KeyValueAccess class can have their attributes used through dot notation (e.g., <code>obj1.obj2.attr</code>).
+Specifies the columns that will be stored in the script log. Each column is the name of an attribute of CGI Wrapper. The <b>Introspect</b> CGI example gives a list of all CGI Wrapper attributes. Note that attributes which are dictionaries, UserDicts or subclasses of MiddleKit's NamedValueAccess class can have their attributes used through dot notation (e.g., <code>obj1.obj2.attr</code>).
</dd>
</dl>
@@ -176,10 +176,18 @@
</dl>
<dl>
+<dt><b>LogErrors</b>
+ <code> = 1</code></dt>
+<dd>
+If true, then CGI Wrapper logs exceptions. Each entry contains the date & time, filename, pathname, exception name & data, and the HTML error message filename (assuming there is one).
+</dd>
+</dl>
+
+<dl>
<dt><b>ErrorLogFilename</b>
<code> = 'Errors.csv'</code></dt>
<dd>
-This is the name of the file where CGI Wrapper logs exceptions if <code>LogErrors</code> is true. Each entry contains the date & time, filename, pathname, exception name & data, and the HTML error message filename (assuming there is one).
+This is the name of the file where CGI Wrapper logs exceptions if <code>LogErrors</code> is true.
</dd>
</dl>
@@ -195,7 +203,7 @@
<dt><b>ErrorMessagesDir</b>
<code> = 'ErrorMsgs'</code></dt>
<dd>
-This is the name of the directory where HTML error messages get stored.
+This is the name of the directory where HTML error messages get stored if <code>SaveErrorMessages</code> is true.
</dd>
</dl>
@@ -230,8 +238,15 @@
</dd>
</dl>
+<dl>
+<dt><b>AdminRemoteAddr</b>
+ <code> = ['127.0.0.1']</code></dt>
+<dd>
+A list of IP addresses or networks from which admin scripts can be accessed.
+</dd>
+</dl>
-<p>You can override any of these values by creating a <code>Config.dict</code> file in the same directory as the wrapper and selectively specifying values in a dictionary like so:</p>
+<p>You can override any of these values by creating a <code>CGIWrapper.config</code> file in the same directory as the wrapper and selectively specifying values in a dictionary like so:</p>
<pre class="py">{
'ExtraPaths': ['Backend', 'ThirdParty'],
@@ -241,12 +256,12 @@
<a name="Running"></a><h3>Running and Testing</h3>
-<p>Let's assume you have a webserver running on a UNIX box and a public HTML directory in your home directory. First, make a link from your public HTML directory to the source directory of the CGI Wrapper:</p>
+<p>Let's assume you have a web server running on a Unix box and a public HTML directory in your home directory. First, make a link from your public HTML directory to the source directory of the CGI Wrapper:</p>
<code>cd ~/public_html
<br>ln -s ~/Projects/Webware/CGIWrapper pycgi</code>
-<p>Note that in the Source directory there is a link to the Examples directory and that the CGI Wrapper will automatically look there (you can configure this; see <a href="#Configuration">Configuration</a>). Therefore you can type a URL like:</p>
+<p>Note that in the Source directory there is an Examples directory and that the CGI Wrapper will automatically look there (you can configure this; see <a href="#Configuration">Configuration</a>). Therefore you can type a URL like:</p>
<code>http://localhost/~echuck/pycgi/server.cgi/Hello</code>
@@ -269,16 +284,18 @@
<tr><td align="right">1251</td><td><a href="Directory">Directory</a></td><td><a href="View?filename=Directory">view</a></td></tr>
</table>
-<p>The above instructions rely on your web server executing any files that end in <code>.cgi</code>. However, some servers require that executable scripts are also located in a special directory (such as <code>cgi-bin</code>) so you may need to take that into consideration when getting CGI Wrapper to work. Please consult your web server admin or your web server docs.</p>
+<p>The above instructions rely on your web server executing any files that end in <code>.cgi</code>. However, some servers require that executable scripts are also located in a special directory (such as <code>cgi-bin</code>) so you may need to take that into consideration when getting CGI Wrapper to work. Please consult your web server admin or your web server docs. You may also have to specify the exact location of the Python interpreter in the first line of the <code>server.cgi</code> script, particularly under Windows.</p>
<a name="Administration"></a><h3>Administration</h3>
<p>CGI Wrapper comes with a script for administration purposes. You can access it by specifying the <code>_admin</code> script in the URL. You typically only have to remember <code>_admin</code> because it contains links to the other scripts.</p>
+<p>Note that access to the admin scripts is restricted to the local host by default, but you can add more hosts or networks for administrators in the configuration.</p>
+
<p>From the administration page, you can view the script log, the error log and the configuration of the server. The error log display also contains links to the archived error messages so that you can browse through them.</p>
-<p>The adminstration scripts are good examples of class-based CGIs so you may wish to read through their code.</p>
+<p>The administration scripts are good examples of class-based CGIs so you may wish to read through their code.</p>
<p>Here's an <a href="SampleAdmin.html">example</a> of the admin page.</p>
@@ -290,13 +307,13 @@
<a name="ClassBasedCGIs"></a><h3>Class-based CGIs</h3>
-<p>As you write CGI scripts, and especially if they are for the same site, you may find that they have several things in common. For example, the generated pages may all have a common toolbar, heading and/or footing. You might also find that you display programmatically collected data in a similiar fashion throughout your pages.</p>
+<p>As you write CGI scripts, and especially if they are for the same site, you may find that they have several things in common. For example, the generated pages may all have a common toolbar, heading and/or footing. You might also find that you display programmatically collected data in a similar fashion throughout your pages.</p>
<p>When you see these kinds of similarities, it's time to start designing a class hierarchy that takes advantage of inheritance, encapsulation and polymorphism in order to save you from duplicative work.</p>
<p>For example your base class could have methods <code>header()</code>, <code>body()</code> and <code>footer()</code> with the header and footer being fully implemented. Subclasses would then only need to override <code>body()</code> and would therefore inherit their look and feel from one source. You could take this much farther by providing several utility methods in the base class that are available to subclasses for use or customization.</p>
-<p>CGI Wrapper provides a hook to support such class-based CGI scripts by checking for a classes in the target script. The <code>ClassNames</code> setting, whose default value is <code>['', 'Page']</code>, controls this behavior. After a script executes, CGI Wrapper checks these classes. The empty string is a special case which specifies a class whose name is the same name as it's containing script (e.g., the class <code>_admin</code> in the script <code>_admin.py</code>).</p>
+<p>CGI Wrapper provides a hook to support such class-based CGI scripts by checking for certain classes in the target script. The <code>ClassNames</code> setting, whose default value is <code>['', 'Page']</code>, controls this behavior. After a script executes, CGI Wrapper checks these classes. The empty string is a special case which specifies a class whose name is the same name as it's containing script (e.g., the class <code>_admin</code> in the script <code>_admin.py</code>).</p>
<p>If a matching class is found, it is automatically instantiated so that you don't have to do so in every script. The instantiation is basically:</p>
@@ -306,7 +323,7 @@
<p>A good example of class-based CGIs are the admin pages for CGI Wrapper. Start by reading <i>AdminPage.py</i> and then continuing with the various admin scripts such as <i>_admin.py</i> and <i>_showConfig.py</i>. All of these are located in the same directory as CGI Wrapper.</p>
-<p>On a final note, if you find that you're developing a sophisticated web-based application with accounts, sessions, persistence, etc. then you should consider using the <a href="../../WebKit/Docs/index.html">WebKit</a>, which is analagous to Apple's WebObjects and Sun's Java Servlets.</p>
+<p>On a final note, if you find that you're developing a sophisticated web-based application with accounts, sessions, persistence, etc. then you should consider using the <a href="../../WebKit/Docs/index.html">WebKit</a>, which is analogous to Apple's WebObjects and Sun's Java Servlets.</p>
<a name="OtherFileTypes"></a><h3>Other File Types</h3>
@@ -320,7 +337,7 @@
<p>Cookies are often an important part of web programming. CGI Wrapper does not provide explicit support for cookies, however, it provides an easily utilized hook for them.</p>
-<p>If upon completion, the target script has a <code>cookies</code> global variable, the CGI Wrapper will print it to stdout. This fits in nicely with the Cookie module written by Timothy O'Malley. You will find a copy of this module in the WebUtils package of Webware for Python. You could also find it by searching for "Cookie" at the Vaults of Parnassus located at <a href="http://www.vex.net/parnassus/">/www.vex.net/parnassus/</a>.</p>
+<p>If upon completion, the target script has a <code>cookies</code> global variable, the CGI Wrapper will print it to stdout. This fits in nicely with the Cookie module written by Timothy O'Malley that is part of the standard library since Python 2.0. There is also a copy of this module in the WebUtils package of Webware for Python.</p>
<a name="Subclassing"></a><h3>Subclassing CGI Wrapper</h3>
@@ -343,7 +360,7 @@
<p><b>server.cgi</b> - Just a Python script with a generic name (that appears in URLs) that imports CGIWrapper.py. By keeping the CGIWrapper.py file separate we get byte code caching (CGIWrapper.pyc) and syntax highlighting when viewing or editing the script.</p>
<p><b>CGIWrapper.py</b> - The main script that does the work.</p>
-<p><b>Config.dict</b> - An optional file containing a dictionary that overrides default configuration settings.</p>
+<p><b>CGIWrapper.config</b> - An optional file containing a dictionary that overrides default configuration settings.</p>
<p><b>Scripts.csv</b> - The log of script executions as described above.</p>
<p><b>Errors.csv</b> - The log of uncaught exceptions including date & time, script filename and archived error message filename.</p>
<p><b>ErrorMsgs/Error-<i>scriptname</i>-<i>YYYY</i>-<i>MM</i>-<i>DD</i>-<i>*</i>.py</b> - Archived error messages.</p>
@@ -357,7 +374,7 @@
<li><a href="RelNotes-0.2.1.html">Version 0.2.1</a></li>
<li><a href="RelNotes-0.2.2.html">Version 0.2.2</a></li>
<li><a href="RelNotes-0.7.html">Version 0.7</a></li>
-<li><a href="RelNotes-0.8.html">Version 0.8</a></li>
+<li><a href="RelNotes-1.0.html">Version 1.0</a></li>
</ul>
@@ -365,7 +382,7 @@
<p>Note: CGI scripts are fine for small features, but if you're developing a full blown web-based application then you typically want more support, persistence and classes. That's where other Webware components like WebKit and MiddleKit come into play.</p>
-<p>Here are some future ideas, with no committments or timelines as to when/if they'll be realized. This is open source, so feel free to jump in!</p>
+<p>Here are some future ideas, with no commitments or timelines as to when/if they'll be realized. This is open source, so feel free to jump in!</p>
<p>The following are in approximate order of the author's perceived priority, but the numbering is mostly for reference.</p>
@@ -375,19 +392,18 @@
<ol>
<li>Examples: Make a Cookie example. (In the meantime, just see the main doc string of Cookie.py in WebUtils.)</li>
<li>Wrapper: When a script produces no output, the CGI Wrapper should report that problem. (This most often happens for class based CGIs with incorrect class names.)</li>
- <li>There should probably be an option to clear the output of a script that raised an uncaught exception. Sometimes that could help in debugging.</li>
+ <li>Wrapper: There should probably be an option to clear the output of a script that raised an uncaught exception. Sometimes that could help in debugging.</li>
<li>Admin: Create a summary page for the script and error logs.</li>
<li>Wrapper: It's intended that the CGIWrapper class could be embedded in a server and a single instance reused several times. The class is not quite there yet.</li>
- <li>Wrapper: CGI scripts never get cached as byte code (.pyc) which would provide a performance boost. 2000-04-17 ce: Check out py_compile module.</li>
+ <li>Wrapper: CGI scripts never get cached as byte code (.pyc) which would provide a performance boost.</li>
<li>Wrapper: The error log columns should be configurable just like the script log columns.</li>
<li>Code review: Misc functions towards bottom of CGIWrapper</li>
<li>Code review: Use of _realStdout and sys.stdout on multiple serve() calls.</li>
<li>Wrapper: Create a subclass of Python's CGI server that uses CGIWrapper. This would include caching the byte code in memory.</li>
<li>Wrapper: htmlErrorPageFilename() uses a "mostly works" technique that could be better. See source.</li>
- <li>Wrapper: Keep a list of file extensions (such as .py .html .pl) mapped to their handlers. When processing a URL, iterate through the list until a file with that extension is found, then serve it up through it's handler.</li>
- <li>There's no password protection on the administration scripts.</li>
- <li>Provide integration (and therefore increased performance) with web servers such as Apache and AOLserver.</li>
- <li>Wrapper: If the script log can't be opened for writing, nothing happens. What's the best action here?</li>
+ <li>Wrapper: Keep a list of file extensions (such as .py .html .pl) mapped to their handlers. When processing a URL, iterate through the list until a file with that extension is found, then serve it up through its handler.</li>
+ <li>Admin: Add password protection on the administration scripts.</li>
+ <li>Wrapper: Provide integration (and therefore increased performance) with web servers such as Apache.</li>
<li>Wrapper: Error e-mails are always in HTML format. It may be useful to have a plain text version for those with more primitive e-mail clients.</li>
</ol>
@@ -396,6 +412,8 @@
<p>Author: Chuck Esterbrook</p>
+<p>Some improvements were made by Christoph Zwerschke.</p>
+
<p>The idea of a CGI wrapper is based on a WebTechniques <a href="http://www.webtechniques.com/archives/1998/02/kuchling/">article</a> by Andrew Kuchling.</p>
<% footer() %>
\ No newline at end of file
Modified: Webware/trunk/CGIWrapper/Examples/Colors.py
==============================================================================
--- Webware/trunk/CGIWrapper/Examples/Colors.py (original)
+++ Webware/trunk/CGIWrapper/Examples/Colors.py Sun Dec 9 05:24:09 2007
@@ -1,39 +1,36 @@
if fields.has_key('bgcolor'):
bgcolor = fields['bgcolor'].value
- bgcolorArg = 'bgcolor=' + bgcolor
+ bgcolorArg = 'bgcolor="%s"' % bgcolor
else:
bgcolor = ''
bgcolorArg = ''
-print '''
+print '''<!DOCTYPE HTML SYSTEM>
<html>
<head>
<title>Colors</title>
</head>
<body %s>
- <p align=center><font size=+1><b>Colors</b></font></p>
-
+ <h1 align="center">Colors</h1>
<center>
- <form>
- bgcolor: <input type=next name=bgcolor value="%s">
- <input type=submit value=Go>
+ <form action="Colors">
+ bgcolor: <input type="text" name="bgcolor" value="%s">
+ <input type="submit" value="Go">
</form>
- </center>
-
- <p><table align=center>
+ <table cellspacing="2" cellpadding="2">
''' % (bgcolorArg, bgcolor)
space = ' '*10
gamma = 2.2 # an approximation for today's CRTs, see "brightness =" below
for r in range(11):
- r = r/10.0
+ r /= 10.0
for g in range(11):
- g = g/10.0
+ g /= 10.0
print '<tr>'
for b in range(11):
- b = b/10.0
+ b /= 10.0
color = '#%02x%02x%02x' % (r*255, g*255, b*255)
# Compute brightness given RGB
brightness = (0.3*r**gamma + 0.6*g**gamma + 0.1*b**gamma)**(1/gamma)
@@ -42,10 +39,11 @@
textcolor = 'white'
else:
textcolor = 'black'
- print '<td bgcolor=%s> <br> <font color=%s>%s</font> </td>' % (color, textcolor, color)
+ print '<td style="color:%s;background-color:%s;">%s</td>' % (textcolor, color, color)
print '</tr>'
print '''
</table>
+ </center>
</body>
</html>'''
Modified: Webware/trunk/CGIWrapper/Examples/Directory.py
==============================================================================
--- Webware/trunk/CGIWrapper/Examples/Directory.py (original)
+++ Webware/trunk/CGIWrapper/Examples/Directory.py Sun Dec 9 05:24:09 2007
@@ -1,21 +1,23 @@
import os
-from stat import *
+from stat import ST_SIZE
-print '''
+print '''%s
<html>
<head>
<title>Webware CGI Examples Directory</title>
</head>
<body>
- <p align=center><font size=+1><b>Webware CGI Examples</b></font></p>
-'''
+ <h1 align="center">Webware CGI Examples</h1>
+''' % wrapper.docType()
def sizeSorter(a, b):
- """
+ """Sort by size
+
Used for sorting when the elements are dictionaries and the
attribute to sort by is 'size'.
+
"""
- return a['size'] - b['size']
+ return int(a['size'] - b['size'])
# Create a list of dictionaries, where each dictionary stores information about
# a particular script.
@@ -29,15 +31,19 @@
scripts.append(script)
scripts.sort(sizeSorter)
-print '<p><table cellspacing=0 align=center>'
-print '<tr> <th align=right>Size</th> <th align=left>Script</th> <th align=left>View</th> </tr>'
+print '<table cellspacing="2" cellpadding="2" align="center">'
+print '<tr>',
+print '<th align="right">Size</th>',
+print '<th align="left">Script</th>',
+print '<th align="left">View</th>',
+print '</tr>'
for script in scripts:
print '<tr>',
print '<td align=right> %d </td>' % script['size'],
- print '<td> <a href=%s>%s</a> </td>' % (script['shortname'], script['shortname']),
- print '<td> <a href=View?filename=%s>view</a> </td>' % script['shortname'],
- print '<tr>'
+ print '<td> <a href="%s">%s</a> </td>' % (script['shortname'], script['shortname']),
+ print '<td> <a href="View?filename=%s">view</a> </td>' % script['shortname'],
+ print '</tr>'
print '</table>'
Modified: Webware/trunk/CGIWrapper/Examples/FormTest.py
==============================================================================
--- Webware/trunk/CGIWrapper/Examples/FormTest.py (original)
+++ Webware/trunk/CGIWrapper/Examples/FormTest.py Sun Dec 9 05:24:09 2007
@@ -1,21 +1,15 @@
-print '''
-
+print '''%s
<html>
+<head><title>FormTest</title></head>
<body>
-
-<form>
-
-<input type=text name=a>
-
-<p>
-
-<input name=button type=submit value=Hello>
-
+<h1>Form Test</h1>
+<form action="FormTest">
+<input type="text" name="text">
+<input name="button" type="submit" value="Submit">
</form>
-
<p>
fields = %s
-
+</p>
</html>
-''' % fields
+''' % (wrapper.docType(), fields)
Modified: Webware/trunk/CGIWrapper/Examples/Hello.py
==============================================================================
--- Webware/trunk/CGIWrapper/Examples/Hello.py (original)
+++ Webware/trunk/CGIWrapper/Examples/Hello.py Sun Dec 9 05:24:09 2007
@@ -1,10 +1,11 @@
-print '''
+print '''%s
<html>
<head>
- <title>Hello</title>
+ <title>Hello, word!</title>
</head>
<body>
- <p>Hello
+ <h1 align="center">Hello, World!</h1>
+ <p align="center">This is CGI Wrapper %s speaking...</p>
</body>
-</html>'''
+</html>''' % (wrapper.docType(), wrapper.version())
Modified: Webware/trunk/CGIWrapper/Examples/Introspect.py
==============================================================================
--- Webware/trunk/CGIWrapper/Examples/Introspect.py (original)
+++ Webware/trunk/CGIWrapper/Examples/Introspect.py Sun Dec 9 05:24:09 2007
@@ -1,13 +1,12 @@
-print '''
+print '''%s
<html>
<head>
<title>Python Introspection</title>
</head>
<body>
- <p><font size=+1>Basic Python Introspection</font>
- <p>
-'''
+ <h2>Basic Python Introspection</h2>
+''' % wrapper.docType()
def printKeys(name, obj):
keys = obj.keys()
@@ -21,9 +20,9 @@
printKeys('headers', headers)
printKeys('wrapper.__dict__', wrapper.__dict__)
-
-
print '''
- <p> <hr> <p> Note that the <a href=Error>Error</a> script results in a much better display of introspection.
+ <hr>
+ <p>Note that the <a href="Error">Error</a> script
+ results in a much better display of introspection.</p>
</body>
</html>'''
Modified: Webware/trunk/CGIWrapper/Examples/Time.py
==============================================================================
--- Webware/trunk/CGIWrapper/Examples/Time.py (original)
+++ Webware/trunk/CGIWrapper/Examples/Time.py Sun Dec 9 05:24:09 2007
@@ -1,15 +1,13 @@
-print '''
+import time
+
+print '''%s
<html>
<head>
<title>Time</title>
</head>
- <body>'''
-
-import time
-
-print '<p>', time.asctime(time.localtime(time.time()))
-
-print '''
+ <body>
+ <h3>Current Time</h3>
+ <p>%s</p>
</body>
-</html>'''
+</html>''' % (wrapper.docType(), time.asctime(time.localtime(time.time())))
Modified: Webware/trunk/CGIWrapper/Examples/View.py
==============================================================================
--- Webware/trunk/CGIWrapper/Examples/View.py (original)
+++ Webware/trunk/CGIWrapper/Examples/View.py Sun Dec 9 05:24:09 2007
@@ -1,29 +1,32 @@
+import os
-print '''
+print '''%s
<html>
<head>
<title>Webware View CGI Source</title>
</head>
<body>
- <p><font size=+1><b>Webware View CGI Source</b></font>
-'''
+ <h1>Webware View CGI Source</h1>
+''' % wrapper.docType()
if not fields.has_key('filename'):
- print '<p>No filename specified.'
+ print '<p>No filename specified.</p>'
else:
if fields.has_key('tabSize'):
tabSize = int(fields['tabSize'].value)
else:
tabSize = 4
- filename = fields['filename'].value
- filename += '.py'
- contents = open(filename).read()
+ filename = os.path.basename(fields['filename'].value) + '.py'
+ try:
+ contents = open(filename).read()
+ except IOError:
+ contents = '(cannot view file)'
if tabSize > 0:
contents = contents.expandtabs(tabSize)
contents = contents.replace('&', '&')
contents = contents.replace('<', '<')
contents = contents.replace('>', '>')
- print '<br><i>%s</i><hr><pre>%s</pre>' % (filename, contents)
+ print '<h2>%s</h2><hr><pre>%s</pre>' % (filename, contents)
print '''
</body>
Added: Webware/trunk/CGIWrapper/_accessDenied.py
==============================================================================
--- (empty file)
+++ Webware/trunk/CGIWrapper/_accessDenied.py Sun Dec 9 05:24:09 2007
@@ -0,0 +1,13 @@
+"""CGIWrapper access denied script."""
+
+headers['status'] = "403 Forbidden"
+
+print '''%s
+<html>
+ <head>
+ <title>Access denied</title>
+ </head>
+ <body>
+ <h1>Access denied</h1>
+ </body>
+</html>''' % wrapper.docType()
Modified: Webware/trunk/CGIWrapper/_admin.py
==============================================================================
--- Webware/trunk/CGIWrapper/_admin.py (original)
+++ Webware/trunk/CGIWrapper/_admin.py Sun Dec 9 05:24:09 2007
@@ -1,8 +1,13 @@
+"""CGIWrapper main admin script."""
+
from time import time, localtime, gmtime, asctime
-from AdminPage import *
+
+from WebUtils.Funcs import urlEncode
+from AdminPage import AdminPage
class Page(AdminPage):
+ """CGIWrapper main administration page."""
def title(self):
return 'Admin'
@@ -10,20 +15,17 @@
def writeBody(self):
curTime = time()
self.writeln('''
- <table align=center cellspacing=0 cellpadding=0 borde=0>
- <tr> <td><b>Version:</b></td> <td>%s</td> </tr>
- <tr> <td><b>Local time:</b></td> <td>%s</td> </tr>
- <tr> <td><b>Global time:</b></td> <td>%s</td> </tr>
- </table>
- ''' % (self._wrapper.version(),
+ <table align="center" cellspacing="2" cellpadding="2" border="0">
+ <tr><th>Version:</th><td>%s</td></tr>
+ <tr><th>Local time:</th><td>%s</td></tr>
+ <tr><th>Global time:</th><td>%s</td></tr>
+ </table>''' % (self._wrapper.version(),
asctime(localtime(curTime)), asctime(gmtime(curTime))))
-
self.startMenu()
- # @@ 2000-04-21 ce: use URLEncode() here.
self.menuItem('Script log contents', '_dumpCSV?filename=%s'
- % self._wrapper.setting('ScriptLogFilename'))
+ % urlEncode(self._wrapper.setting('ScriptLogFilename')))
self.menuItem('Error log contents', '_dumpErrors?filename=%s'
- % self._wrapper.setting('ErrorLogFilename'))
+ % urlEncode(self._wrapper.setting('ErrorLogFilename')))
self.menuItem('Show config', '_showConfig')
self.endMenu()
@@ -31,23 +33,26 @@
<!--
begin-parse
{
- 'Version': %s,
- 'LocalTime': %s,
- 'GlobalTime': %s
+ 'Version': %r,
+ 'LocalTime': %r,
+ 'GlobalTime': %r
}
end-parse
--->''' % (repr(self._wrapper.version()),
- repr(localtime(curTime)), repr(gmtime(curTime))))
+-->''' % (self._wrapper.version(), localtime(curTime), gmtime(curTime)))
def startMenu(self):
- self.writeln('''<p> </p><table align="center" border="0"'
- ' cellspacing="2" cellpadding="2" bgcolor="#FFFFDD">'
- '<tr bgcolor="black"><td align="center">'
- '<b style="color:white;font-family:Arial,Helvetica,sans-serif">Menu</b>'
- '</td></tr>''')
+ self.write('''
+ <div style="font-size:12pt;font-family:Arial,Helvetica,sans-serif">
+ <table align="center" border="0" cellspacing="2" cellpadding="2" bgcolor="#E8E8F0">
+ <tr bgcolor="#101040"><th align="center" style="color:white">Menu</th></tr>
+ <tr><td>''')
def menuItem(self, title, url):
- self.writeln('<tr><td><a href="%s">%s</a></td></tr>' % (url, title))
+ self.write('''
+ <tr><td align="center"><a href="%s">%s</a></td></tr>'''
+ % (url, title))
def endMenu(self):
- self.writeln('</table>')
+ self.writeln('''
+ </table>
+ </div>''')
Modified: Webware/trunk/CGIWrapper/_dumpCSV.py
==============================================================================
--- Webware/trunk/CGIWrapper/_dumpCSV.py (original)
+++ Webware/trunk/CGIWrapper/_dumpCSV.py Sun Dec 9 05:24:09 2007
@@ -1,25 +1,36 @@
-import os, string
-from AdminPage import *
+"""CGIWrapper dump CSV admin script."""
+
+import os
+
+from WebUtils.Funcs import htmlEncode
+from AdminPage import AdminPage
def LoadCSV(filename):
+ """Load CSV file.
+
+ Loads a CSV (comma-separated value) file from disk and returns it as a
+ list of rows where each row is a list of values (which are always strings).
+
"""
- Loads a CSV (comma-separated value) file from disk and returns
- it as a list of rows where each row is a list of values (which
- are always strings).
- """
- f = open(filename)
- rows = []
- while 1:
- line = f.readline()
- if not line:
- break
- rows.append(string.split(line, ','))
- f.close()
+ try:
+ f = open(filename)
+ try:
+ rows = []
+ while 1:
+ line = f.readline()
+ if not line:
+ break
+ rows.append(line.split(','))
+ finally:
+ f.close()
+ except IOError:
+ rows = []
return rows
class _dumpCSV(AdminPage):
+ """CGIWrapper class that dumps a CSV file."""
def __init__(self, dict):
AdminPage.__init__(self, dict)
@@ -34,13 +45,14 @@
def writeBody(self):
rows = LoadCSV(self._filename)
- self.writeln('<p><table align=center border=0 cellpadding=2 cellspacing=2 bgcolor=#EEEEEE>')
+ self.writeln('<table align="center" border="0" cellpadding="2" cellspacing="2">')
# Head row gets special formatting
- self._headings = map(lambda name: string.strip(name), rows[0])
- self.writeln('<tr bgcolor=black>')
+ self._headings = map(lambda name: name.strip(), rows[0])
+ self.writeln('<tr>')
for value in self._headings:
- self.writeln('<td><font face="Arial, Helvetica" color=white><b> ', value, ' </b></font></td>')
+ self.writeln('<th style="color:white;font-family:Arial,Helvetica,sans-serif" bgcolor="#101040">',
+ value, '</th>')
self.writeln('</tr>')
# Data rows
@@ -49,7 +61,8 @@
self.writeln('<tr>')
colIndex = 0
for value in row:
- self.writeln('<td> ', self.cellContents(rowIndex, colIndex, value), ' </td>')
+ self.writeln('<td style="color:#111111" bgcolor="#EEEEEE">',
+ self.cellContents(rowIndex, colIndex, value), '</td>')
colIndex += 1
self.writeln('</tr>')
rowIndex += 1
@@ -57,9 +70,10 @@
self.writeln('</table>')
def cellContents(self, rowIndex, colIndex, value):
+ """Return cell contents of CSV file.
+
+ This is a hook for subclasses to customize the contents of a cell
+ based on any criteria (including location).
+
"""
- This is a hook for subclasses to customize the
- contents of a cell based on any criteria (including
- location).
- """
- return value
+ return htmlEncode(value)
Modified: Webware/trunk/CGIWrapper/_dumpErrors.py
==============================================================================
--- Webware/trunk/CGIWrapper/_dumpErrors.py (original)
+++ Webware/trunk/CGIWrapper/_dumpErrors.py Sun Dec 9 05:24:09 2007
@@ -1,15 +1,18 @@
+"""CGIWrapper dump errors admin script."""
+
+from WebUtils.Funcs import htmlEncode
from _dumpCSV import _dumpCSV
class _dumpErrors(_dumpCSV):
def cellContents(self, rowIndex, colIndex, value):
- """
- This is a hook for subclasses to customize the
- contents of a cell based on any criteria (including
- location).
+ """Return cell contents of CSV file.
+
+ This subclass adds a link to error files.
+
"""
if self._headings[colIndex] == 'error report filename':
- return '<a href="%s">%s</a>' % (value, value)
+ return '<a href="_viewError?filename=%s">%s</a>' % (value, value)
else:
- return value
+ return htmlEncode(value)
Modified: Webware/trunk/CGIWrapper/_showConfig.py
==============================================================================
--- Webware/trunk/CGIWrapper/_showConfig.py (original)
+++ Webware/trunk/CGIWrapper/_showConfig.py Sun Dec 9 05:24:09 2007
@@ -1,4 +1,5 @@
-from AdminPage import *
+from CGIWrapper import htDictionary
+from AdminPage import AdminPage
class _showConfig(AdminPage):
@@ -7,5 +8,4 @@
return 'Config'
def writeBody(self):
- import CGIWrapper
- self.writeln(CGIWrapper.htDictionary(self._wrapper.config()))
+ self.writeln(htDictionary(self._wrapper.config()))
Added: Webware/trunk/CGIWrapper/_viewError.py
==============================================================================
--- (empty file)
+++ Webware/trunk/CGIWrapper/_viewError.py Sun Dec 9 05:24:09 2007
@@ -0,0 +1,10 @@
+"""CGIWrapper view error file admin script."""
+
+import os
+
+filename = os.path.basename(fields['filename'].value)
+filename = os.path.join(wrapper.setting('ErrorMessagesDir'), filename)
+try:
+ print open(filename).read()
+except IOError:
+ print 'Cannot read error file.'
|
| Thread | Author | Date |
|---|---|---|
| [Webware-checkins] r7120 - in Webware/trunk/CGIWrapper: . Docs Examples | <updates@we...> |