📄 publisher.py
字号:
elif func_code.co_argcount < len(func_code.co_varnames): names = func_code.co_varnames[func_code.co_argcount:] if name in names: i = list(names).index(name) if i is not None: return (1, func_code.co_consts[i+1]) return (0, None) (found_auth, __auth__) = lookup('__auth__') if found_auth and type(__auth__) == types.CodeType: __auth__ = new.function(__auth__, func_globals) (found_access, __access__) = lookup('__access__') if found_access and type(__access__) == types.CodeType: __access__ = new.function(__access__, func_globals) (found_realm, __auth_realm__) = lookup('__auth_realm__') if found_realm: realm = __auth_realm__ else: if hasattr(object, "__auth__"): __auth__ = object.__auth__ found_auth = 1 if hasattr(object, "__access__"): __access__ = object.__access__ found_access = 1 if found_auth or found_access: # because ap_get_basic insists on making sure that AuthName and # AuthType directives are specified and refuses to do anything # otherwise (which is technically speaking a good thing), we # have to do base64 decoding ourselves. # # to avoid needless header parsing, user and password are parsed # once and the are received as arguments if not user and req.headers_in.has_key("Authorization"): try: s = req.headers_in["Authorization"][6:] s = base64.decodestring(s) user, passwd = s.split(":", 1) except: raise apache.SERVER_RETURN, apache.HTTP_BAD_REQUEST if found_auth: if not user: # note that Opera supposedly doesn't like spaces around "=" below s = 'Basic realm="%s"' % realm req.err_headers_out["WWW-Authenticate"] = s raise apache.SERVER_RETURN, apache.HTTP_UNAUTHORIZED if callable(__auth__): rc = __auth__(req, user, passwd) else: if type(__auth__) is DictionaryType: rc = __auth__.has_key(user) and __auth__[user] == passwd else: rc = __auth__ if not rc: s = 'Basic realm = "%s"' % realm req.err_headers_out["WWW-Authenticate"] = s raise apache.SERVER_RETURN, apache.HTTP_UNAUTHORIZED if found_access: if callable(__access__): rc = __access__(req, user) else: if type(__access__) in (ListType, TupleType): rc = user in __access__ else: rc = __access__ if not rc: raise apache.SERVER_RETURN, apache.HTTP_FORBIDDEN return realm, user, passwd### Those are the traversal and publishing rules #### tp_rules is a dictionary, indexed by type, with tuple values.# The first item in the tuple is a boolean telling if the object can be traversed (default is True)# The second item in the tuple is a boolen telling if the object can be published (default is True)tp_rules = {}# by default, built-in types cannot be traversed, but can be publisheddefault_builtins_tp_rule = (False, True)for t in types.__dict__.values(): if isinstance(t, type): tp_rules[t]=default_builtins_tp_rule# those are the exceptions to the previous rulestp_rules.update({ # Those are not traversable nor publishable ModuleType : (False, False), BuiltinFunctionType : (False, False), # This may change in the near future to (False, True) ClassType : (False, False), TypeType : (False, False), # Publishing a generator may not seem to makes sense, because # it can only be done once. However, we could get a brand new generator # each time a new-style class property is accessed. GeneratorType : (False, True), # Old-style instances are traversable InstanceType : (True, True),})# types which are not referenced in the tp_rules dictionary will be traversable# AND publishable default_tp_rule = (True, True)def resolve_object(req, obj, object_str, realm=None, user=None, passwd=None): """ This function traverses the objects separated by . (period) to find the last one we're looking for. """ parts = object_str.split('.') first_object = True for obj_str in parts: # path components starting with an underscore are forbidden if obj_str[0]=='_': req.log_error('Cannot traverse %s in %s because ' 'it starts with an underscore' % (obj_str, req.unparsed_uri), apache.APLOG_WARNING) raise apache.SERVER_RETURN, apache.HTTP_FORBIDDEN if first_object: first_object = False else: # if we're not in the first object (which is the module) # we're going to check whether be can traverse this type or not rule = tp_rules.get(type(obj), default_tp_rule) if not rule[0]: req.log_error('Cannot traverse %s in %s because ' '%s is not a traversable object' % (obj_str, req.unparsed_uri, obj), apache.APLOG_WARNING) raise apache.SERVER_RETURN, apache.HTTP_FORBIDDEN # we know it's OK to call getattr # note that getattr can really call some code because # of property objects (or attribute with __get__ special methods)... try: obj = getattr(obj, obj_str) except AttributeError: raise apache.SERVER_RETURN, apache.HTTP_NOT_FOUND # we process the authentication for the object realm, user, passwd = process_auth(req, obj, realm, user, passwd) # we're going to check if the final object is publishable rule = tp_rules.get(type(obj), default_tp_rule) if not rule[1]: req.log_error('Cannot publish %s in %s because ' '%s is not publishable' % (obj_str, req.unparsed_uri, obj), apache.APLOG_WARNING) raise apache.SERVER_RETURN, apache.HTTP_FORBIDDEN return obj# This regular expression is used to test for the presence of an HTML header# tag, written in upper or lower case.re_html = re.compile(r"</HTML\s*>\s*$",re.I)re_charset = re.compile(r"charset\s*=\s*([^\s;]+)",re.I);def publish_object(req, object): if callable(object): # To publish callables, we call them an recursively publish the result # of the call (as done by util.apply_fs_data) req.form = util.FieldStorage(req, keep_blank_values=1) return publish_object(req,util.apply_fs_data(object, req.form, req=req))# TODO : we removed this as of mod_python 3.2, let's see if we can put it back# in mod_python 3.3 # elif hasattr(object,'__iter__'):# # # To publish iterables, we recursively publish each item# # This way, generators can be published# result = False# for item in object:# result |= publish_object(req,item)# return result# else: if object is None: # Nothing to publish return False elif isinstance(object,UnicodeType): # We've got an Unicode string to publish, so we have to encode # it to bytes. We try to detect the character encoding # from the Content-Type header if req._content_type_set: charset = re_charset.search(req.content_type) if charset: charset = charset.group(1) else: # If no character encoding was set, we use UTF8 charset = 'UTF8' req.content_type += '; charset=UTF8' else: # If no character encoding was set, we use UTF8 charset = 'UTF8' result = object.encode(charset) else: charset = None result = str(object) if not req._content_type_set: # make an attempt to guess content-type # we look for a </HTML in the last 100 characters. # re.search works OK with a negative start index (it starts from 0 # in that case) if re_html.search(result,len(result)-100): req.content_type = 'text/html' else: req.content_type = 'text/plain' if charset is not None: req.content_type += '; charset=%s'%charset # Write result even if req.method is 'HEAD' as Apache # will discard the final output anyway. Truncating # output here if req.method is 'HEAD' is likely the # wrong thing to do as it may cause problems for any # output filters. See MODPYTHON-105 for details. We # also do not flush output as that will prohibit use # of 'CONTENT_LENGTH' filter to add 'Content-Length' # header automatically. See MODPYTHON-107 for details. req.write(result, 0) return True
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -