00001
00002
00003 import neo_cgi, neo_cs
00004 import sys, os, string
00005 import time
00006 from log import *
00007
00008
00009 class NoPageName(Exception):
00010 pass
00011 class NoDisplayMethod(Exception):
00012 pass
00013
00014
00015 class Redirected(Exception):
00016 pass
00017 class DisplayDone(Exception):
00018 pass
00019 class DisplayError(Exception):
00020 pass
00021 class MultipleActionsError(Exception):
00022 pass
00023
00024 class Context:
00025 def __init__ (self):
00026 self.argv = sys.argv
00027 self.stdin = sys.stdin
00028 self.stdout = sys.stdout
00029 self.stderr = sys.stderr
00030 self.environ = os.environ
00031
00032 def setStatus(self, request, status):
00033 if request:
00034 request['status'] = str(status)
00035
00036
00037 class CSPage:
00038 _pagename = None
00039
00040 def __init__(self, context, pagename=None,readDefaultHDF=1,israwpage=0,
00041 parseCGI=1, makePUT=0, **parms):
00042 if pagename is None: pagename = self._pagename
00043 if not pagename: raise NoPageName("missing pagename")
00044 self.pagename = pagename
00045 self.readDefaultHDF = readDefaultHDF
00046 self._israwpage = israwpage
00047 self.context = context
00048 self._pageparms = parms
00049
00050 self._error_template = None
00051
00052 self.page_start_time = time.time()
00053
00054 if makePUT:
00055 context.environ['REQUEST_METHOD'] = 'PUT'
00056
00057 neo_cgi.cgiWrap(context.stdin, context.stdout, context.environ)
00058 neo_cgi.IgnoreEmptyFormVars(1)
00059 self.ncgi = neo_cgi.CGI()
00060
00061 if parseCGI:
00062 self.ncgi.parse()
00063
00064 self._path_num = 0
00065 domain = self.ncgi.hdf.getValue("CGI.ServerName","")
00066 domain = self.ncgi.hdf.getValue("HTTP.Host", domain)
00067 self.domain = domain
00068
00069 self.setPaths([self.ncgi.hdf.getValue("CGI.DocumentRoot","")])
00070
00071 self._sent_headers = 0
00072 self._reply_headers = {}
00073 self._reply_code = 200
00074
00075 if self.ncgi.hdf.getValue("CGI.HTTPS", ""):
00076 self.http = "https://"
00077 else:
00078 self.http = "http://"
00079
00080 try:
00081 self.subclassinit()
00082 except:
00083 SHOULD_DISPLAY = 0
00084 DISPLAY_ERROR = 1
00085
00086 import handle_error
00087 handle_error.handleException("Display Failed!")
00088 ERROR_MESSAGE = handle_error.exceptionString()
00089 return
00090
00091 def __setitem__(self, key, value):
00092 self._reply_headers[string.lower(key)] = value
00093 self.ncgi.hdf.setValue("cgiout.other.%s" % key, "%s: %s" % (key, value))
00094
00095 def __getitem__(self, key):
00096 return self._reply_headers[string.lower(key)]
00097
00098 def has_key(self, key):
00099 return self._reply_headers.has_key(string.lower(key))
00100
00101 def subclassinit(self):
00102 pass
00103
00104 def clearPaths(self):
00105 self.ncgi.hdf.removeTree("hdf.loadpaths")
00106
00107 def setPaths(self, paths):
00108 for path in paths:
00109 self.ncgi.hdf.setValue("hdf.loadpaths.%d" % self._path_num, path)
00110 self._path_num = self._path_num + 1
00111
00112 def redirectUri(self,redirectTo):
00113 ncgi = self.ncgi
00114 if ncgi.hdf.getIntValue("Cookie.debug",0) == 1:
00115 ncgi.hdf.setValue("CGI.REDIRECT_TO",redirectTo)
00116
00117
00118 cs = neo_cs.CS(ncgi.hdf)
00119 self['Content-Type'] = "text/html"
00120 template = """
00121 Redirect
00122 <br><br>
00123 <a href="<?cs var:CGI.REDIRECT_TO ?>"><?cs var:CGI.REDIRECT_TO ?></a>
00124 """
00125 cs.parseStr(template)
00126 page = cs.render()
00127
00128 self.push(page)
00129
00130 self.push("<PRE>\n")
00131 self.push(neo_cgi.htmlEscape(ncgi.hdf.dump()) + "\n")
00132 self.push("</PRE>\n")
00133 raise DisplayDone()
00134
00135 self.context.setStatus(self, 302)
00136 self.ncgi.redirectUri(redirectTo)
00137 raise Redirected("redirected To: %s" % redirectTo)
00138
00139
00140
00141
00142 def setup(self):
00143 pass
00144
00145 def display(self):
00146 raise NoDisplayMethod("no display method present in %s" % repr(self))
00147
00148 def main(self):
00149 hdf = self.ncgi.hdf
00150
00151 def __call(method):
00152 if method.im_func.func_code.co_argcount == 2:
00153 method(hdf)
00154 else:
00155 method()
00156
00157 __call(self.setup)
00158
00159 self.handle_actions()
00160
00161 __call(self.display)
00162
00163
00164
00165 def handle_actions(self):
00166 hdf = self.ncgi.hdf
00167
00168 hdfobj = hdf.getObj("Query.Action")
00169 if hdfobj:
00170 firstchild = hdfobj.child()
00171 if firstchild:
00172 action = firstchild.name()
00173 if firstchild.next():
00174 raise MultipleActionsError("multiple actions present!!!")
00175
00176 method_name = "Action_%s" % action
00177 method = getattr(self,method_name)
00178 if method.im_func.func_code.co_argcount == 2:
00179 apply(method,[hdf])
00180 else:
00181 apply(method,[])
00182
00183 def start(self):
00184 SHOULD_DISPLAY = 1
00185 if self._israwpage:
00186 SHOULD_DISPLAY = 0
00187
00188 ncgi = self.ncgi
00189
00190 if self.readDefaultHDF:
00191 try:
00192 if not self.pagename is None:
00193 ncgi.hdf.readFile("%s.hdf" % self.pagename)
00194 except:
00195 debug("Error reading HDF file: %s.hdf" % (self.pagename))
00196
00197 DISPLAY_ERROR = 0
00198 ERROR_MESSAGE = ""
00199
00200 try:
00201 self.main()
00202 except DisplayDone:
00203 SHOULD_DISPLAY = 0
00204 except Redirected:
00205
00206 SHOULD_DISPLAY = 0
00207 except DisplayError, num:
00208 ncgi.hdf.setValue("Query.error", str(num))
00209 if self._error_template:
00210 ncgi.hdf.setValue("Content", self._error_template)
00211 else:
00212 DISPLAY_ERROR = 1
00213 except:
00214 SHOULD_DISPLAY = 0
00215 DISPLAY_ERROR = 1
00216
00217 import handle_error
00218 handle_error.handleException("Display Failed!")
00219 ERROR_MESSAGE = handle_error.exceptionString()
00220
00221 if DISPLAY_ERROR:
00222
00223
00224
00225
00226 self['Content-Type'] = "text/html"
00227
00228
00229 self.push("<head>")
00230 self.push('''
00231 <script type="text/javascript">
00232 function toggleDebugInfo() {
00233 var tb = document.getElementById('%s');
00234 if (tb == null) return;
00235 tb.style.display = tb.style.display ? '' : 'none';
00236 }
00237 </script>
00238 <style type="text/css">
00239 .cgitb {background: #E6EAF0; border: 1px solid #4D6180; direction: ltr;}
00240 .cgitb p {margin: 0.5em 0; padding: 5px 10px; text-align: left;}
00241 .cgitb ol {margin: 0}
00242 .cgitb li {margin: 0.25em 0;}
00243 .cgitb h1, .cgitb h2, .cgitb h3 {padding: 5px 10px; margin: 0; background: #4D6180; color: white;}
00244 .cgitb h1 {font-size: 1.3em;}
00245 .cgitb h2 {font-size: 1em; margin-top: 1em;}
00246 .cgitb h3 {font-size: 1em;}
00247 .cgitb .frames {margin: 0; padding: 0; color: #606060}
00248 .cgitb .frames li {display: block;}
00249 .cgitb .call {padding: 5px 10px; background: #A3B4CC; color: black}
00250 .cgitb .context {padding: 0; font-family: monospace; }
00251 .cgitb .context li {display: block; white-space: pre;}
00252 .cgitb .context li.highlight {background: #C0D3F0; color: black}
00253 .cgitb .variables {padding: 5px 10px; font-family: monospace;}
00254 .cgitb .variables li {display: inline;}
00255 .cgitb .variables li:after {content: ", ";}
00256 .cgitb .variables li:last-child:after {content: "";}
00257 .cgitb .exception {border: 1px solid #4D6180; margin: 10px}
00258 .cgitb .exception h3 {background: #4D6180; color: white;}
00259 .cgitb .exception p {color: black;}
00260 .cgitb .exception ul {padding: 0 10px; font-family: monospace;}
00261 .cgitb .exception li {display: block;}
00262
00263 .cgitb .buttons {margin: 0.5em 0; padding: 5px 10px;}
00264 .cgitb .buttons li {display: inline; margin: 0; padding: 0 0.25em;}
00265 </style>
00266 ''')
00267
00268 self.push("</head>")
00269
00270 self.push("<H1> Error in Page </H1>\n")
00271 self.push("A copy of this error report has been submitted to the developers. ")
00272 self.push("The details of the error report are below.")
00273
00274 self.push(handle_error.exceptionString())
00275
00276
00277 self.push("<HR>\n")
00278 self.push("<PRE>")
00279 self.push(neo_cgi.htmlEscape(ncgi.hdf.dump()))
00280 self.push("</PRE>")
00281
00282
00283 etime = time.time() - self.page_start_time
00284 ncgi.hdf.setValue("CGI.debug.execute_time","%f" % (etime))
00285
00286
00287 if SHOULD_DISPLAY and self.pagename:
00288 debug_output = ncgi.hdf.getIntValue("page.debug",ncgi.hdf.getIntValue("Cookie.debug",0))
00289
00290
00291 if ncgi.hdf.getValue("Query.debug","") == ncgi.hdf.getValue("Config.DebugPassword","1"):
00292 ncgi.hdf.setValue("Config.DebugPassword","CSPage.py DEBUG hijack (%s)" %
00293 ncgi.hdf.getValue("Config.DebugPassword",""))
00294 debug_output = 1
00295
00296 if not debug_output:
00297 ncgi.hdf.setValue("Config.CompressionEnabled","1")
00298 else:
00299 ncgi.hdf.setValue("Config.CompressionEnabled","0")
00300
00301
00302 template_name = ncgi.hdf.getValue("Content","%s.cs" % self.pagename)
00303
00304
00305 try:
00306 self.context.setStatus(self, 200)
00307 ncgi.display(template_name)
00308 self._sent_headers = 1
00309 except:
00310 self['Content-Type'] = 'text/html'
00311 self.push("CSPage: Error occured\n")
00312 import handle_error
00313 self.push("<pre>" + handle_error.exceptionString() + "</pre>")
00314 debug_output = 1
00315
00316
00317
00318 if debug_output:
00319 self.push("<HR>\n")
00320 self.push("Execution Time: %5.3f<BR><HR>" % (etime))
00321 self.push("<PRE>")
00322 self.push(neo_cgi.htmlEscape(ncgi.hdf.dump()))
00323 self.push("</PRE>")
00324
00325
00326
00327 script_name = ncgi.hdf.getValue("CGI.ScriptName","")
00328 if script_name:
00329 script_name = string.split(script_name,"/")[-1]
00330
00331 log ("[%s] etime/dtime: %5.3f/%5.3f %s (%s)" % (self.domain, etime, time.time() - etime - self.page_start_time, script_name, self.pagename))
00332 return self._reply_code
00333
00334
00335
00336
00337 def output(self, str):
00338 try:
00339 if len(str) > 8196:
00340 import cStringIO
00341 fp = cStringIO.StringIO(str)
00342 while 1:
00343 data = fp.read(8196*8)
00344 if not data: break
00345 self.context.stdout.write(data)
00346 else:
00347 self.context.stdout.write(str)
00348 except IOError, reason:
00349 log("IOError: %s" % (repr(reason)))
00350 raise DisplayDone()
00351
00352 def done(self):
00353 if not self._sent_headers: self.error(500)
00354 self._sent_headers = 0
00355
00356 raise DisplayDone()
00357
00358 def push(self, data):
00359 if not self._sent_headers:
00360 headerdata = self.send_headers(dont_send=1)
00361 self.output(headerdata + data)
00362 else:
00363 self.output(data)
00364
00365
00366 def send_headers(self, dont_send=0):
00367 self._sent_headers = 1
00368
00369 message = gHTTPResponses[self._reply_code]
00370
00371 if self._reply_code != 200:
00372
00373
00374 pass
00375 self.context.setStatus(self, self._reply_code)
00376 self['connection'] = 'close'
00377
00378 headers = []
00379
00380 for (key, value) in self._reply_headers.items():
00381 headers.append('%s: %s' % (key, value))
00382 headers.append('\r\n')
00383
00384 if dont_send == 0:
00385 self.push(string.join(headers, '\r\n'))
00386 else:
00387 return string.join(headers, '\r\n')
00388
00389
00390 def allQuery (self, s):
00391 l = []
00392 if self.ncgi.hdf.getValue ("Query.%s.0" % s, ""):
00393 obj = self.ncgi.hdf.getChild ("Query.%s" % s)
00394 while obj:
00395 l.append(obj.value())
00396 obj = obj.next()
00397 else:
00398 t = self.ncgi.hdf.getValue ("Query.%s" % s, "")
00399 if t: l.append(t)
00400 return l
00401
00402
00403 def error(self, code, reason=None):
00404 self._reply_code = code
00405 message = gHTTPResponses[code]
00406 s = DEFAULT_ERROR_MESSAGE % {
00407 'code': code, 'message': message, 'reason': reason
00408 }
00409
00410
00411
00412
00413
00414 self.context.stdout.write("Content-Type: text/html\n")
00415 self.context.setStatus(self, code)
00416 self.context.stdout.write("Status: %s\n" % code)
00417 self.context.stdout.write(s)
00418
00419
00420 raise DisplayDone()
00421
00422
00423
00424 gHTTPResponses = {
00425 100: "Continue",
00426 101: "Switching Protocols",
00427 200: "OK",
00428 201: "Created",
00429 202: "Accepted",
00430 203: "Non-Authoritative Information",
00431 204: "No Content",
00432 205: "Reset Content",
00433 206: "Partial Content",
00434 300: "Multiple Choices",
00435 301: "Moved Permanently",
00436 302: "Moved Temporarily",
00437 303: "See Other",
00438 304: "Not Modified",
00439 305: "Use Proxy",
00440 400: "Bad Request",
00441 401: "Unauthorized",
00442 402: "Payment Required",
00443 403: "Forbidden",
00444 404: "Not Found",
00445 405: "Method Not Allowed",
00446 406: "Not Acceptable",
00447 407: "Proxy Authentication Required",
00448 408: "Request Time-out",
00449 409: "Conflict",
00450 410: "Gone",
00451 411: "Length Required",
00452 412: "Precondition Failed",
00453 413: "Request Entity Too Large",
00454 414: "Request-URI Too Large",
00455 415: "Unsupported Media Type",
00456 500: "Internal Server Error",
00457 501: "Not Implemented",
00458 502: "Bad Gateway",
00459 503: "Service Unavailable",
00460 504: "Gateway Time-out",
00461 505: "HTTP Version not supported"
00462 }
00463
00464
00465 DEFAULT_ERROR_MESSAGE = string.join(
00466 ['',
00467 '<head>',
00468 '<title>%(code)d %(message)s</title>',
00469 '</head>',
00470 '<body>',
00471 '<h1>%(message)s</h1>',
00472 '<p>Error code %(code)d.',
00473 '<p>Message: %(message)s.',
00474 '<p>Reason:\n <pre>%(reason)s</pre>',
00475 '</body>',
00476 ''
00477 ],
00478 '\r\n'
00479 )