⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 psp.py

📁 Mod_python is an Apache module that embeds the Python interpreter within the server. With mod_python
💻 PY
字号:
 # vim: set sw=4 expandtab : # # Copyright 2004 Apache Software Foundation  #  # Licensed under the Apache License, Version 2.0 (the "License"); you # may not use this file except in compliance with the License.  You # may obtain a copy of the License at # #      http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied.  See the License for the specific language governing # permissions and limitations under the License. # # This file originally written by Sterling Hughes # # $Id: psp.py 472053 2006-11-07 10:11:01Z grahamd $import apache, Session, util, _pspimport _apacheimport sysimport osimport marshalimport newfrom cgi import escapeimport anydbm, whichdbimport tempfile# dbm types for cachedbm_types = {}tempdir = tempfile.gettempdir()def path_split(filename):    dir, fname = os.path.split(filename)    if sys.platform.startswith("win"):        dir += "\\"    else:        dir += "/"    return dir, fnamedef code2str(c):    ctuple = (c.co_argcount, c.co_nlocals, c.co_stacksize, c.co_flags,              c.co_code, c.co_consts, c.co_names, c.co_varnames, c.co_filename,              c.co_name, c.co_firstlineno, c.co_lnotab)        return marshal.dumps(ctuple)def str2code(s):    return new.code(*marshal.loads(s))class PSPInterface:    def __init__(self, req, filename, form):        self.req = req        self.filename = filename        self.error_page = None        self.form = form    def set_error_page(self, page):        if page and page[0] == '/':            # relative to document root            self.error_page = PSP(self.req, self.req.document_root() + page)        else:            # relative to same dir we're in            dir = path_split(self.filename)[0]            self.error_page = PSP(self.req, dir + page)    def apply_data(self, object):        if not self.form:            if not hasattr(self.req, 'form'):                # no existing form, so need to create one,                # form has to be saved back to request object                # so that error page can access it if need be                self.form = util.FieldStorage(self.req, keep_blank_values=1)                self.req.form = self.form            else:                self.form = self.req.form        return util.apply_fs_data(object, self.form, req=self.req)    def redirect(self, location, permanent=0):        util.redirect(self.req, location, permanent)class PSP:    code = None    dbmcache = None    def __init__(self, req, filename=None, string=None, vars={}):        if (string and filename):            raise ValueError, "Must specify either filename or string"        self.req, self.vars = req, vars        if not filename and not string:            filename = req.filename        self.filename, self.string = filename, string        if filename:            # if filename is not absolute, default to our guess            # of current directory            if not os.path.isabs(filename):                base = os.path.split(req.filename)[0]                self.filename = os.path.join(base, filename)            self.load_from_file()        else:            cached = mem_scache.get(string)            if cached:                self.code = cached            else:                source = _psp.parsestring(string)                code = compile(source, "__psp__", "exec")                mem_scache.store(string,code)                self.code = code    def cache_get(self, filename, mtime):        opts = self.req.get_options()        if opts.has_key("mod_python.psp.cache_database_filename"):            self.dbmcache = opts["mod_python.psp.cache_database_filename"]        elif opts.has_key("PSPDbmCache"):            # For backwards compatability with versions            # of mod_python prior to 3.3.            self.dbmcache = opts["PSPDbmCache"]        if self.dbmcache:            cached = dbm_cache_get(self.req.server, self.dbmcache,                                   filename, mtime)            if cached:                return cached        cached = mem_fcache.get(filename, mtime)        if cached:            return cached    def cache_store(self, filename, mtime, code):        if self.dbmcache:            dbm_cache_store(self.req.server, self.dbmcache,                            filename, mtime, code)        else:            mem_fcache.store(filename, mtime, code)    def cfile_get(self, filename, mtime):        # check for a file ending with 'c' (precompiled file)        name, ext = os.path.splitext(filename)        cname = name + ext[:-1] + 'c'        if os.path.isfile(cname):            cmtime = os.path.getmtime(cname)            if cmtime >= mtime:                return str2code(open(cname).read())    def load_from_file(self):        filename = self.filename        if not os.path.isfile(filename):            raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND        mtime = os.path.getmtime(filename)        # check cache        code = self.cache_get(filename, mtime)        # check for precompiled file        if not code:            code = self.cfile_get(filename, mtime)        # finally parse and compile        if not code:            dir, fname = path_split(self.filename)            source = _psp.parse(fname, dir)            code = compile(source, filename, "exec")        # store in cache        self.cache_store(filename, mtime, code)        self.code = code    def run(self, vars={}, flush=0):        code, req = self.code, self.req        # does this code use session?        session = None        if "session" in code.co_names:            if not hasattr(req, 'session'):                # no existing session, so need to create one,                # session has to be saved back to request object                # to avoid deadlock if error page tries to use it                req.session = session = Session.Session(req)         # does this code use form?        form = None        if "form" in code.co_names:            if not hasattr(req, 'form'):                # no existing form, so need to create one,                # form has to be saved back to request object                # so that error page can access it if need be                form = util.FieldStorage(req, keep_blank_values=1)                req.form = form            else:                form = req.form        # create psp interface object        psp = PSPInterface(req, self.filename, form)        try:            global_scope = globals().copy()            global_scope.update({"req":req, "form":form, "psp":psp})            # strictly speaking, session attribute only needs            # to be populated if referenced, but historically            # code has always populated it even if None, so            # preserve that just in case changing it breaks            # some users code            if hasattr(req, 'session'):                global_scope.update({"session":req.session})            else:                global_scope.update({"session":None})            global_scope.update(self.vars) # passed in __init__()            global_scope.update(vars)      # passed in run()            try:                exec code in global_scope                if flush:                    req.flush()                                # the mere instantiation of a session changes it                # (access time), so it *always* has to be saved                if hasattr(req, 'session'):                    req.session.save()            except:                et, ev, etb = sys.exc_info()                if psp.error_page:                    # run error page                    psp.error_page.run({"exception": (et, ev, etb)}, flush)                else:                    raise et, ev, etb        finally:            # if session was created here, unlock it and don't leave            # it behind in request object in unlocked state as it            # will just cause problems if then used by subsequent code            if session is not None:                session.unlock()                del req.session    def __str__(self):        self.req.content_type = 'text/html'        self.run()        return ""    def display_code(self):        """        Display a niceliy HTML-formatted side-by-side of        what PSP generated next to orinial code.        """        req, filename = self.req, self.filename        # Because of caching, source code is most often not        # available in this object, so we read it here        # (instead of trying to get it in __init__ somewhere)        dir, fname = path_split(filename)        source = open(filename).read().splitlines()        pycode = _psp.parse(fname, dir).splitlines()        source = [s.rstrip() for s in source]        pycode = [s.rstrip() for s in pycode]        req.write("<table>\n<tr>")        for s in ("", "&nbsp;PSP-produced Python Code:",                  "&nbsp;%s:" % filename):            req.write("<td><tt>%s</tt></td>" % s)        req.write("</tr>\n")        n = 1        for line in pycode:            req.write("<tr>")            left = escape(line).replace("\t", " "*4).replace(" ", "&nbsp;")            if len(source) < n:                right = ""            else:                right = escape(source[n-1]).replace("\t", " "*4).replace(" ", "&nbsp;")            for s in ("%d.&nbsp;" % n,                      "<font color=blue>%s</font>" % left,                      "&nbsp;<font color=green>%s</font>" % right):                req.write("<td><tt>%s</tt></td>" % s)            req.write("</tr>\n")            n += 1        req.write("</table>\n")def parse(filename, dir=None):    if dir:        return _psp.parse(filename, dir)    else:        return _psp.parse(filename)def parsestring(str):    return _psp.parsestring(str)def handler(req):    req.content_type = "text/html"    config = req.get_config()    debug = debug = int(config.get("PythonDebug", 0))    if debug and req.filename[-1] == "_":        p = PSP(req, req.filename[:-1])        p.display_code()    else:        p = PSP(req)        p.run()    return apache.OKdef dbm_cache_type(dbmfile):    global dbm_types    if dbm_types.has_key(dbmfile):        return dbm_types[dbmfile]    module = whichdb.whichdb(dbmfile)    if module:        dbm_type = __import__(module)        dbm_types[dbmfile] = dbm_type        return dbm_type    else:        # this is a new file        return anydbmdef dbm_cache_store(srv, dbmfile, filename, mtime, val):       dbm_type = dbm_cache_type(dbmfile)    # NOTE: acquiring a lock for the dbm file (also applies to dbm_cache_get)    # See http://issues.apache.org/jira/browse/MODPYTHON-69    # In mod_python versions < 3.2 "pspcache" was used as the lock key.    # ie.  _apache._global_lock(srv, key, index)    # Assuming there are 32 mutexes (the default in 3.1.x), "pspcache"    # will hash to one of  31 mutexes (index 0 is reserved). Therefore    # there is a 1 in 31 chance for a hash collision if a session is    # used in the same request, which would result in a deadlock. This    # has been confirmed by testing.    # We can avoid this by using index 0 and setting the key to None.    # Lock index 0 is also used by DbmSession for locking it's dbm file,     # but since the lock is not held for the duration of the request there    # should not be any additional deadlock issues. Likewise, the lock    # here is only held for a short time, so it will not interfere    # with DbmSession file locking.      _apache._global_lock(srv, None, 0)    try:        dbm = dbm_type.open(dbmfile, 'c')        dbm[filename] = "%d %s" % (mtime, code2str(val))    finally:        try: dbm.close()        except: pass        _apache._global_unlock(srv, None, 0)def dbm_cache_get(srv, dbmfile, filename, mtime):    dbm_type = dbm_cache_type(dbmfile)    _apache._global_lock(srv, None, 0)    try:        dbm = dbm_type.open(dbmfile, 'c')        try:            entry = dbm[filename]            t, val = entry.split(" ", 1)            if long(t) == mtime:                return str2code(val)        except KeyError:            return None    finally:        try: dbm.close()        except: pass        _apache._global_unlock(srv, None, 0)class HitsCache:    def __init__(self, size=512):        self.cache = {}        self.size = size    def store(self, key, val):        self.cache[key] = (1, val)        if len(self.cache) > self.size:            self.clean()    def get(self, key):        if self.cache.has_key(key):            hits, val = self.cache[key]            self.cache[key] = (hits+1, val)            return val        else:            return None    def clean(self):                byhits = [(n[1], n[0]) for n in self.cache.items()]        byhits.sort()        # delete enough least hit entries to make cache 75% full        for item in byhits[:len(self.cache)-int(self.size*.75)]:            val, key = item            del self.cache[key]mem_scache = HitsCache()class FileCache(HitsCache):    def store(self, filename, mtime, code):        self.cache[filename] = (1, mtime, code)        if len(self.cache) > self.size:            self.clean()    def get(self, filename, mtime):        try:            hits, c_mtime, code = self.cache[filename]            if mtime != c_mtime:                del self.cache[filename]                return None            else:                self.cache[filename] = (hits+1, mtime, code)                return code        except KeyError:            return Nonemem_fcache = FileCache()

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -