CSPage.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 import neo_cgi, neo_cs
00004 import sys, os, string
00005 import time
00006 from log import *
00007 
00008 # errors thrown...
00009 class NoPageName(Exception):
00010   pass
00011 class NoDisplayMethod(Exception):
00012   pass
00013 
00014 # errors signaled back to here
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 #            ncgi.display("dbg/redirect.cs")
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     ## methods to be overridden in subclass when necessary:
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         #warn(hdf.writeString())
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         # call page main function!
00200         try:
00201             self.main()
00202         except DisplayDone:
00203             SHOULD_DISPLAY = 0
00204         except Redirected:
00205             # catch redirect exceptions
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             #print "Content-Type: text/html\n\n"
00223 
00224             # print the page
00225 
00226             self['Content-Type'] = "text/html"
00227 
00228             # print the page
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             # print debug info always on page error...
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         #warn("excute_time", etime)
00286 
00287         if SHOULD_DISPLAY and self.pagename:
00288             debug_output = ncgi.hdf.getIntValue("page.debug",ncgi.hdf.getIntValue("Cookie.debug",0))
00289 
00290             # hijack the built-in debug output method...
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             # default display
00302             template_name = ncgi.hdf.getValue("Content","%s.cs" % self.pagename)
00303             # ncgi.hdf.setValue ("cgiout.charset", "utf-8");
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             # debug output
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               # ncgi.hdf.setValue("hdf.DEBUG",ncgi.hdf.dump())
00325               # ncgi.display("debug.cs")
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     # a protected output function to catch the output errors that occur when
00335     # the server is either restarted or the user pushes the stop button on the
00336     # browser
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         #self['status'] = "%s %s" % (self._reply_code, message)
00373         #self.context.setStatus(self, self._reply_code)
00374         pass
00375       self.context.setStatus(self, self._reply_code)
00376       self['connection'] = 'close'
00377 
00378       headers = []
00379       #headers.append(self.response(self._reply_code))
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 #      self['Content-Length'] = len(s)
00411 #      self['Content-Type'] = 'text/html'
00412 
00413 #      self.push(s)
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 #      self.done()
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 # Default error message
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         )


pyclearsilver
Author(s): Scott Hassan/hassan@willowgarage.com
autogenerated on Wed Apr 23 2014 10:35:42