2021SC@SDUSC
本周继续分析剩余零散的代码
error_printer.py是WSGI中间件捕获应用程序抛出的DAVErrors并返回适当的响应。该文件中只包含一个名为ErrorPrinter的类。
ErrorPrinter主要代码集中在函数def __call__(self, environ, start_response)中。主要用来捕获DAVError和non-DAVError类错误。
代码及其注释
#拦截start_response
sub_app_start_response = util.SubAppStartResponse()
try:
try:
#request_server app可能是一个生成器(例如GET处理程序),所以我们必须迭代-而不
#是 返回self.next_app(..)!否则,我们无法在这里捕获异常。
response_started = False
app_iter = self.next_app(environ, sub_app_start_response)
for v in app_iter:
# Start response (the first time)
if not response_started:
# Success!
start_response(
sub_app_start_response.status,
sub_app_start_response.response_headers,
sub_app_start_response.exc_info,
)
response_started = True
yield v
# 结束迭代器
if hasattr(app_iter, "close"):
app_iter.close()
# 启动响应(如果还没有完成)
if not response_started:
# Success!
start_response(
sub_app_start_response.status,
sub_app_start_response.response_headers,
sub_app_start_response.exc_info,
)
return
except DAVError as e:
_logger.debug("re-raising {}".format(e))
raise
except Exception as e:
# 捕获 non-DAVError异常
if self.catch_all_exceptions:
#捕获所有异常,返回500内部错误
# 回溯。Print_exc (10, environ.get("wsgi.errors")或sys.stderr)
_logger.error("{}".format(traceback.format_exc(10)))
raise as_DAVError(e)
else:
_logger.error(
"Caught Exception\n{}".format(traceback.format_exc(10))
)
# 回溯。sys.stderr print_exc (10)
raise
fs_dav_provider.py:实现从文件系统提供资源的DAV提供者。
类:“~ wsgidav.fs_dav_provider。FilesystemProvider实现DAV资源。发布文件系统的提供程序。如果传入' ' readonly=True ' ',写尝试将引发HTTP_FORBIDDEN。这个provider创建了:class:`~wsgidav.fs_dav_provider.FileResource`的实例和:类:“~ wsgidav.fs_dav_provider。表示文件和目录分别。
class FileResource(DAVNonCollection)表示一个现有的DAV资源实例。请参见_DAVResource、DAVNonCollection和FilesystemProvider。
该类中的def get_content函数负责作为阅读流的开放内容。看到DAVResource.get_content ()。
def get_content(self):
assert not self.is_collection
# GC issue 28, 57: if we open in text mode, \r\n is converted to one byte.
# So the file size reported by Windows differs from len(..), thus
# content-length will be wrong.
return open(self._file_path, "rb", BUFFER_SIZE)
def begin_write(self, content_type=None):开放内容作为写作流。看到DAVResource.begin_write ()
代码
def begin_write(self, content_type=None):
assert not self.is_collection
if self.provider.readonly:
raise DAVError(HTTP_FORBIDDEN)
# _logger.debug("begin_write: {}, {}".format(self._file_path, "wb"))
# GC issue 57: always store as binary
return open(self._file_path, "wb", BUFFER_SIZE)
def delete(self):删除此资源或集合(递归)。参考DAVResource.delete ()
代码
def delete(self):
if self.provider.readonly:
raise DAVError(HTTP_FORBIDDEN)
os.unlink(self._file_path)
self.remove_all_properties(True)
self.remove_all_locks(True)
类FolderResource(DAVCollection):表示单个现有文件系统文件夹DAV资源。
请参见_DAVResource、DAVCollection和FilesystemProvider。
def get_member_names(self)函数是该类中的核心代码。其主要功能是
返回直接集合成员名列表(utf-8编码)。
参见DAVCollection.get_member_names()在Windows NT/2k/XP和Unix上,如果path是一个Unicode对象,结果将是一个Unicode对象列表。不可解码的文件名仍将作为字符串对象返回
如果我们不要求unicode,例如Vista可能会返回一个'?'而不是一个特殊字符。这个名字将无法使用
构建一个引用此资源的独特URL。
代码
def get_member_names(self):
nameList = []
# self._file_path is unicode, so os.listdir returns unicode as well
assert compat.is_unicode(self._file_path)
for name in os.listdir(self._file_path):
if not compat.is_unicode(name):
name = name.decode(sys.getfilesystemencoding())
assert compat.is_unicode(name)
# Skip non files (links and mount points)
fp = os.path.join(self._file_path, name)
if not os.path.isdir(fp) and not os.path.isfile(fp):
_logger.debug("Skipping non-file {!r}".format(fp))
continue
# name = name.encode("utf8")
name = compat.to_native(name)
nameList.append(name)
return nameList
改文件中第三个核心类class FilesystemProvider(DAVProvider)是一个文件系统提供商。
def _loc_to_file_path(self, path, environ=None):是其主要函数。负责将资源路径转换为unicode绝对文件路径。可选的environ参数可能是有用的,例如在root_folder_path中针对每个用户的子文件夹chroot。
代码
def _loc_to_file_path(self, path, environ=None):
root_path = self.root_folder_path
assert root_path is not None
assert compat.is_native(root_path)
assert compat.is_native(path)
path_parts = path.strip("/").split("/")
file_path = os.path.abspath(os.path.join(root_path, *path_parts))
if not file_path.startswith(root_path):
raise RuntimeError(
"Security exception: tried to access file outside root: {}".format(
file_path
)
)
# Convert to unicode
file_path = util.to_unicode_safe(file_path)
return file_path