def __call__(self, environ, start_response): path = environ["PATH_INFO"] dav_res = None if environ["wsgidav.provider"]: dav_res = environ["wsgidav.provider"].get_resource_inst(path, environ) if ( environ["REQUEST_METHOD"] in ("GET", "HEAD") and dav_res and dav_res.is_collection ): if util.get_content_length(environ) != 0: self._fail( HTTP_MEDIATYPE_NOT_SUPPORTED, "The server does not handle any body content.", ) if environ["REQUEST_METHOD"] == "HEAD": return util.send_status_response( environ, start_response, HTTP_OK, is_head=True ) # Support DAV mount (http://www.ietf.org/rfc/rfc4709.txt) if self.dir_config.get("davmount") and "davmount" in environ.get( "QUERY_STRING", "" ): collectionUrl = util.make_complete_url(environ) collectionUrl = collectionUrl.split("?", 1)[0] res = compat.to_bytes(DAVMOUNT_TEMPLATE.format(collectionUrl)) # TODO: support <dm:open>%s</dm:open> start_response( "200 OK", [ ("Content-Type", "application/davmount+xml"), ("Content-Length", str(len(res))), ("Cache-Control", "private"), ("Date", util.get_rfc1123_time()), ], ) return [res] context = self._get_context(environ, dav_res) res = self.template.render(**context) res = compat.to_bytes(res) start_response( "200 OK", [ ("Content-Type", "text/html"), ("Content-Length", str(len(res))), ("Cache-Control", "private"), ("Date", util.get_rfc1123_time()), ], ) return [res] return self.next_app(environ, start_response)
def send_digest_auth_response(self, environ, start_response): realm_name = self.domain_controller.get_domain_realm( environ["PATH_INFO"], environ) random.seed() serverkey = hex(random.getrandbits(32))[2:] etagkey = calc_hexdigest(environ["PATH_INFO"]) timekey = str(time.time()) nonce_source = timekey + calc_hexdigest(timekey + ":" + etagkey + ":" + serverkey) nonce = calc_base64(nonce_source) wwwauthheaders = 'Digest realm="{}", nonce="{}", algorithm=MD5, qop="auth"'.format( realm_name, nonce) _logger.debug("401 Not Authorized for realm '{}' (digest): {}".format( realm_name, wwwauthheaders)) body = compat.to_bytes(self.get_error_message()) start_response( "401 Not Authorized", [ ("WWW-Authenticate", wwwauthheaders), ("Content-Type", "text/html"), ("Content-Length", str(len(body))), ("Date", util.get_rfc1123_time()), ], ) return [body]
def send_digest_auth_response(self, environ, start_response): realm = self.domain_controller.get_domain_realm(environ["PATH_INFO"], environ) random.seed() serverkey = hex(random.getrandbits(32))[2:] etagkey = calc_hexdigest(environ["PATH_INFO"]) timekey = str(time.time()) nonce_source = timekey + calc_hexdigest( timekey + ":" + etagkey + ":" + serverkey ) nonce = calc_base64(nonce_source) wwwauthheaders = 'Digest realm="{}", nonce="{}", algorithm=MD5, qop="auth"'.format( realm, nonce ) _logger.debug( "401 Not Authorized for realm '{}' (digest): {}".format( realm, wwwauthheaders ) ) body = compat.to_bytes(self.error_message_401) start_response( "401 Not Authorized", [ ("WWW-Authenticate", wwwauthheaders), ("Content-Type", "text/html"), ("Content-Length", str(len(body))), ("Date", util.get_rfc1123_time()), ], ) return [body]
def __call__(self, environ, start_response): path = environ["PATH_INFO"] # We want to answer OPTIONS(*), even if no handler was registered for # the top-level realm (e.g. required to map drive letters). provider = environ["wsgidav.provider"] # Hotfix for WinXP / Vista: accept '/' for a '*' if environ["REQUEST_METHOD"] == "OPTIONS" and path in ("/", "*"): # Answer HTTP 'OPTIONS' method on server-level. # From RFC 2616: # If the Request-URI is an asterisk ("*"), the OPTIONS request is # intended to apply to the server in general rather than to a specific # resource. Since a server's communication options typically depend on # the resource, the "*" request is only useful as a "ping" or "no-op" # type of method; it does nothing beyond allowing the client to test the # capabilities of the server. For example, this can be used to test a # proxy for HTTP/1.1 compliance (or lack thereof). dav_compliance_level = "1,2" if ( provider is None or provider.is_readonly() or provider.lock_manager is None ): dav_compliance_level = "1" headers = [ ("Content-Type", "text/html"), ("Content-Length", "0"), ("DAV", dav_compliance_level), ("Date", util.get_rfc1123_time()), ] if environ["wsgidav.config"].get("add_header_MS_Author_Via", False): headers.append(("MS-Author-Via", "DAV")) start_response("200 OK", headers) yield b"" return if provider is None: raise DAVError( HTTP_NOT_FOUND, "Could not find resource provider for '{}'".format(path) ) # Let the appropriate resource provider for the realm handle the # request app = RequestServer(provider) app_iter = app(environ, start_response) for v in app_iter: yield v if hasattr(app_iter, "close"): app_iter.close() return
def send_basic_auth_response(self, environ, start_response): realmname = self._domaincontroller.get_domain_realm( environ["PATH_INFO"], environ) _logger.debug( "401 Not Authorized for realm '{}' (basic)".format(realmname)) wwwauthheaders = "Basic realm=\"" + realmname + "\"" body = compat.to_bytes(self.get_error_message()) start_response("401 Not Authorized", [ ("WWW-Authenticate", wwwauthheaders), ("Content-Type", "text/html"), ("Content-Length", str(len(body))), ("Date", util.get_rfc1123_time()), ]) return [body]
def send_basic_auth_response(self, environ, start_response): realm = self.domain_controller.get_domain_realm(environ["PATH_INFO"], environ) _logger.debug("401 Not Authorized for realm '{}' (basic)".format(realm)) wwwauthheaders = 'Basic realm="' + realm + '"' body = compat.to_bytes(self.error_message_401) start_response( "401 Not Authorized", [ ("WWW-Authenticate", wwwauthheaders), ("Content-Type", "text/html"), ("Content-Length", str(len(body))), ("Date", util.get_rfc1123_time()), ], ) return [body]
def _get_context(self, environ, davres): """ @see: http://www.webdav.org/specs/rfc4918.html#rfc.section.9.4 """ assert davres.is_collection dirConfig = environ["wsgidav.config"].get("dir_browser", {}) isReadOnly = environ["wsgidav.provider"].is_readonly() context = { "htdocs": (self.config.get("mount_path") or "") + ASSET_SHARE, "rows": [], "version": __version__, "displaypath": compat.unquote(davres.get_href()), "url": davres.get_href(), # util.make_complete_url(environ), "parentUrl": util.get_uri_parent(davres.get_href()), "config": dirConfig, "is_readonly": isReadOnly, } trailer = dirConfig.get("response_trailer") if trailer is True: trailer = "${version} - ${time}" if trailer: trailer = trailer.replace( "${version}", "<a href='https://github.com/mar10/wsgidav/'>WsgiDAV/{}</a>".format( __version__ ), ) trailer = trailer.replace("${time}", util.get_rfc1123_time()) context["trailer"] = trailer rows = context["rows"] # Ask collection for member info list dirInfoList = davres.get_directory_info() if dirInfoList is None: # No pre-build info: traverse members dirInfoList = [] childList = davres.get_descendants(depth="1", addSelf=False) for res in childList: di = res.get_display_info() href = res.get_href() classes = [] if res.is_collection: classes.append("directory") if not isReadOnly and not res.is_collection: ext = os.path.splitext(href)[1].lstrip(".").lower() officeType = msOfficeExtToTypeMap.get(ext) if officeType: if dirConfig.get("ms_sharepoint_plugin"): classes.append("msoffice") elif dirConfig.get("ms_sharepoint_urls"): href = "ms-{}:ofe|u|{}".format(officeType, href) entry = { "href": href, "class": " ".join(classes), "displayName": res.get_display_name(), "lastModified": res.get_last_modified(), "is_collection": res.is_collection, "contentLength": res.get_content_length(), "displayType": di.get("type"), "displayTypeComment": di.get("typeComment"), } dirInfoList.append(entry) # ignore_patterns = dirConfig.get("ignore", []) if compat.is_basestring(ignore_patterns): ignore_patterns = ignore_patterns.split(",") for entry in dirInfoList: # Skip ignore patterns ignore = False for pat in ignore_patterns: if fnmatch(entry["displayName"], pat): _logger.debug("Ignore {}".format(entry["displayName"])) ignore = True break if ignore: continue # lastModified = entry.get("lastModified") if lastModified is None: entry["strModified"] = "" else: entry["strModified"] = util.get_rfc1123_time(lastModified) entry["strSize"] = "-" if not entry.get("is_collection"): contentLength = entry.get("contentLength") if contentLength is not None: entry["strSize"] = util.byte_number_string(contentLength) rows.append(entry) # sort sort = "name" if sort == "name": rows.sort( key=lambda v: "{}{}".format( not v["is_collection"], v["displayName"].lower() ) ) if "http_authenticator.username" in environ: context["username"] = ( environ.get("http_authenticator.username") or "anonymous" ) context["realm"] = environ.get("http_authenticator.realm") return context
def __call__(self, environ, start_response): realm_name = self.domain_controller.get_domain_realm( environ["PATH_INFO"], environ) _logger.debug("realm '{}'".format(realm_name)) # _logger.debug("{}".format(environ)) force_allow = False if HOTFIX_WIN_AcceptAnonymousOptions and environ[ "REQUEST_METHOD"] == "OPTIONS": _logger.warning("No authorization required for OPTIONS method") force_allow = True if force_allow or not self.domain_controller.require_authentication( realm_name, environ): # no authentication needed _logger.debug( "No authorization required for realm '{}'".format(realm_name)) environ["http_authenticator.realm"] = realm_name environ["http_authenticator.user_name"] = "" return self.next_app(environ, start_response) if self._trusted_auth_header and environ.get( self._trusted_auth_header): # accept a user_name that was injected by a trusted upstream server _logger.debug( "Accept trusted user_name {}='{}'for realm '{}'".format( self._trusted_auth_header, environ.get(self._trusted_auth_header), realm_name, )) environ["http_authenticator.realm"] = realm_name environ["http_authenticator.user_name"] = environ.get( self._trusted_auth_header) return self.next_app(environ, start_response) if "HTTP_AUTHORIZATION" in environ: authheader = environ["HTTP_AUTHORIZATION"] authmatch = self._header_method.search(authheader) authmethod = "None" if authmatch: authmethod = authmatch.group(1).lower() if authmethod == "digest" and self._accept_digest: return self.auth_digest_auth_request(environ, start_response) elif authmethod == "digest" and self._accept_basic: return self.send_basic_auth_response(environ, start_response) elif authmethod == "basic" and self._accept_basic: return self.auth_basic_auth_request(environ, start_response) # The requested auth method is not supported. elif self._default_digest and self._accept_digest: return self.send_digest_auth_response(environ, start_response) elif self._accept_basic: return self.send_basic_auth_response(environ, start_response) _logger.warn( "HTTPAuthenticator: respond with 400 Bad request; Auth-Method: {}" .format(authmethod)) start_response( "400 Bad Request", [("Content-Length", "0"), ("Date", util.get_rfc1123_time())], ) return [""] if self._default_digest: return self.send_digest_auth_response(environ, start_response) return self.send_basic_auth_response(environ, start_response)
def __call__(self, environ, start_response): realm = self.domain_controller.get_domain_realm(environ["PATH_INFO"], environ) environ["wsgidav.auth.realm"] = realm environ["wsgidav.auth.user_name"] = "" # The domain controller MAY set those values depending on user's # authorization: environ["wsgidav.auth.roles"] = None environ["wsgidav.auth.permissions"] = None # _logger.debug( # "HTTPAuthenticator realm({}): '{}'".format(environ["PATH_INFO"], realm) # ) # _logger.debug("{}".format(environ)) force_logout = False if "logout" in environ.get("QUERY_STRING", ""): force_logout = True _logger.warning("Force logout") force_allow = False if self.win_accept_anonymous_options and environ["REQUEST_METHOD"] == "OPTIONS": _logger.warning("No authorization required for OPTIONS method") force_allow = True if force_allow or not self.domain_controller.require_authentication( realm, environ ): # No authentication needed # _logger.debug("No authorization required for realm '{}'".format(realm)) # environ["wsgidav.auth.realm"] = realm # environ["wsgidav.auth.user_name"] = "" return self.next_app(environ, start_response) if self.trusted_auth_header and environ.get(self.trusted_auth_header): # accept a user_name that was injected by a trusted upstream server _logger.debug( "Accept trusted user_name {}='{}'for realm '{}'".format( self.trusted_auth_header, environ.get(self.trusted_auth_header), realm, ) ) # environ["wsgidav.auth.realm"] = realm environ["wsgidav.auth.user_name"] = environ.get(self.trusted_auth_header) return self.next_app(environ, start_response) if "HTTP_AUTHORIZATION" in environ and not force_logout: auth_header = environ["HTTP_AUTHORIZATION"] auth_match = self._header_method.search(auth_header) auth_method = "None" if auth_match: auth_method = auth_match.group(1).lower() if auth_method == "digest" and self.accept_digest: return self.handle_digest_auth_request(environ, start_response) elif auth_method == "digest" and self.accept_basic: return self.send_basic_auth_response(environ, start_response) elif auth_method == "basic" and self.accept_basic: return self.handle_basic_auth_request(environ, start_response) # The requested auth method is not supported. elif self.default_to_digest and self.accept_digest: return self.send_digest_auth_response(environ, start_response) elif self.accept_basic: return self.send_basic_auth_response(environ, start_response) _logger.warning( "HTTPAuthenticator: respond with 400 Bad request; Auth-Method: {}".format( auth_method ) ) start_response( "400 Bad Request", [("Content-Length", "0"), ("Date", util.get_rfc1123_time())], ) return [""] if self.default_to_digest: return self.send_digest_auth_response(environ, start_response) return self.send_basic_auth_response(environ, start_response)
def __call__(self, environ, start_response): # Intercept start_response sub_app_start_response = util.SubAppStartResponse() try: try: # request_server app may be a generator (for example the GET handler) # So we must iterate - not return self.next_app(..)! # Otherwise the we could not catch exceptions here. 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 # Close out iterator if hasattr(app_iter, "close"): app_iter.close() # Start response (if it hasn't been done yet) 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: # Caught a non-DAVError if self._catch_all_exceptions: # Catch all exceptions to return as 500 Internal Error # traceback.print_exc(10, environ.get("wsgi.errors") or sys.stderr) _logger.error("{}".format(traceback.format_exc(10))) raise as_DAVError(e) else: _logger.error("Caught Exception\n{}".format( traceback.format_exc(10))) # traceback.print_exc(10, sys.stderr) raise except DAVError as e: _logger.debug("caught {}".format(e)) status = get_http_status_string(e) # Dump internal errors to console if e.value == HTTP_INTERNAL_ERROR: tb = traceback.format_exc(10) _logger.error( "Caught HTTPRequestException(HTTP_INTERNAL_ERROR)\n{}". format(tb)) # traceback.print_exc(10, environ.get("wsgi.errors") or sys.stdout) _logger.error("e.srcexception:\n{}".format(e.srcexception)) elif e.value in (HTTP_NOT_MODIFIED, HTTP_NO_CONTENT): # _logger.warn("Forcing empty error response for {}".format(e.value)) # See paste.lint: these code don't have content start_response(status, [("Content-Length", "0"), ("Date", util.get_rfc1123_time())]) yield b"" return # If exception has pre-/post-condition: return as XML response, # else return as HTML content_type, body = e.get_response_page() # TODO: provide exc_info=sys.exc_info()? start_response( status, [ ("Content-Type", content_type), ("Content-Length", str(len(body))), ("Date", util.get_rfc1123_time()), ], ) yield body return
def __call__(self, environ, start_response): # Intercept start_response sub_app_start_response = util.SubAppStartResponse() try: try: # request_server app may be a generator (for example the GET handler) # So we must iterate - not return self.next_app(..)! # Otherwise the we could not catch exceptions here. 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 # Close out iterator if hasattr(app_iter, "close"): app_iter.close() # Start response (if it hasn't been done yet) 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: # Caught a non-DAVError if self.catch_all_exceptions: # Catch all exceptions to return as 500 Internal Error # traceback.print_exc(10, environ.get("wsgi.errors") or sys.stderr) _logger.error("{}".format(traceback.format_exc(10))) raise as_DAVError(e) else: _logger.error( "Caught Exception\n{}".format(traceback.format_exc(10)) ) # traceback.print_exc(10, sys.stderr) raise except DAVError as e: _logger.debug("caught {}".format(e)) status = get_http_status_string(e) # Dump internal errors to console if e.value == HTTP_INTERNAL_ERROR: tb = traceback.format_exc(10) _logger.error( "Caught HTTPRequestException(HTTP_INTERNAL_ERROR)\n{}".format(tb) ) # traceback.print_exc(10, environ.get("wsgi.errors") or sys.stdout) _logger.error("e.src_exception:\n{}".format(e.src_exception)) elif e.value in (HTTP_NOT_MODIFIED, HTTP_NO_CONTENT): # _logger.warning("Forcing empty error response for {}".format(e.value)) # See paste.lint: these code don't have content start_response( status, [("Content-Length", "0"), ("Date", util.get_rfc1123_time())] ) yield b"" return # If exception has pre-/post-condition: return as XML response, # else return as HTML content_type, body = e.get_response_page() # TODO: provide exc_info=sys.exc_info()? start_response( status, [ ("Content-Type", content_type), ("Content-Length", str(len(body))), ("Date", util.get_rfc1123_time()), ], ) yield body return
def _get_context(self, environ, dav_res): """ @see: http://www.webdav.org/specs/rfc4918.html#rfc.section.9.4 """ assert dav_res.is_collection is_readonly = environ["wsgidav.provider"].is_readonly() context = { "htdocs": (self.config.get("mount_path") or "") + ASSET_SHARE, "rows": [], "version": __version__, "display_path": compat.unquote(dav_res.get_href()), "url": dav_res.get_href(), # util.make_complete_url(environ), "parent_url": util.get_uri_parent(dav_res.get_href()), "config": self.dir_config, "is_readonly": is_readonly, "access": "read-only" if is_readonly else "read-write", "is_authenticated": False, } trailer = self.dir_config.get("response_trailer") if trailer is True: #trailer = "${version} - ${time}" trailer = "Shihira Fung - ${time}" if trailer: trailer = trailer.replace( "${version}", "<a href='https://github.com/mar10/wsgidav/'>WsgiDAV/{}</a>".format( __version__ ), ) trailer = trailer.replace("${time}", util.get_rfc1123_time()) context["trailer"] = trailer rows = context["rows"] # Ask collection for member info list dirInfoList = dav_res.get_directory_info() if dirInfoList is None: # No pre-build info: traverse members dirInfoList = [] childList = dav_res.get_descendants(depth="1", add_self=False) for res in childList: di = res.get_display_info() href = res.get_href() ofe_prefix = None tr_classes = [] a_classes = [] if res.is_collection: tr_classes.append("directory") if not is_readonly and not res.is_collection: ext = os.path.splitext(href)[1].lstrip(".").lower() officeType = msOfficeExtToTypeMap.get(ext) if officeType: if self.dir_config.get("ms_sharepoint_support"): ofe_prefix = "ms-{}:ofe|u|".format(officeType) a_classes.append("msoffice") # elif self.dir_config.get("ms_sharepoint_plugin"): # a_classes.append("msoffice") # elif self.dir_config.get("ms_sharepoint_urls"): # href = "ms-{}:ofe|u|{}".format(officeType, href) entry = { "href": href, "ofe_prefix": ofe_prefix, "a_class": " ".join(a_classes), "tr_class": " ".join(tr_classes), "display_name": res.get_display_name(), "last_modified": res.get_last_modified(), "is_collection": res.is_collection, "content_length": res.get_content_length(), "display_type": di.get("type"), "display_type_comment": di.get("typeComment"), } dirInfoList.append(entry) # ignore_patterns = self.dir_config.get("ignore", []) if compat.is_basestring(ignore_patterns): ignore_patterns = ignore_patterns.split(",") ignored_list = [] for entry in dirInfoList: # Skip ignore patterns ignore = False for pat in ignore_patterns: if fnmatch(entry["display_name"], pat): ignored_list.append(entry["display_name"]) # _logger.debug("Ignore {}".format(entry["display_name"])) ignore = True break if ignore: continue # last_modified = entry.get("last_modified") if last_modified is None: entry["str_modified"] = "" else: import time entry["str_modified"] = time.strftime("%b %d %Y, %H:%M:%S", time.localtime(last_modified)) entry["str_size"] = "-" if not entry.get("is_collection"): content_length = entry.get("content_length") if content_length is not None: for unit in ['Bytes', 'KiB', 'MiB', 'GiB']: if content_length < 1024: content_length = "%.2f %s" % (content_length, unit) break content_length /= 1024.0 entry["str_size"] = content_length rows.append(entry) if ignored_list: _logger.debug( "Dir browser ignored {} entries: {}".format( len(ignored_list), ignored_list ) ) # sort sort = "name" if sort == "name": rows.sort( key=lambda v: "{}{}".format( not v["is_collection"], v["display_name"].lower() ) ) if "wsgidav.auth.user_name" in environ: context.update( { "is_authenticated": True, "user_name": (environ.get("wsgidav.auth.user_name") or "anonymous"), "realm": environ.get("wsgidav.auth.realm"), "user_roles": ", ".join(environ.get("wsgidav.auth.roles") or []), "user_permissions": ", ".join( environ.get("wsgidav.auth.permissions") or [] ), } ) return context
def _get_context(self, environ, dav_res): """ @see: http://www.webdav.org/specs/rfc4918.html#rfc.section.9.4 """ assert dav_res.is_collection is_readonly = environ["wsgidav.provider"].is_readonly() context = { "htdocs": (self.config.get("mount_path") or "") + ASSET_SHARE, "rows": [], "version": __version__, "display_path": compat.unquote(dav_res.get_href()), "url": dav_res.get_href(), # util.make_complete_url(environ), "parent_url": util.get_uri_parent(dav_res.get_href()), "config": self.dir_config, "is_readonly": is_readonly, "access": "read-only" if is_readonly else "read-write", "is_authenticated": False, } trailer = self.dir_config.get("response_trailer") if trailer is True: trailer = "${version} - ${time}" if trailer: trailer = trailer.replace( "${version}", "<a href='https://github.com/mar10/wsgidav/'>WsgiDAV/{}</a>".format( __version__ ), ) trailer = trailer.replace("${time}", util.get_rfc1123_time()) context["trailer"] = trailer rows = context["rows"] # Ask collection for member info list dirInfoList = dav_res.get_directory_info() if dirInfoList is None: # No pre-build info: traverse members dirInfoList = [] childList = dav_res.get_descendants(depth="1", add_self=False) for res in childList: di = res.get_display_info() href = res.get_href() ofe_prefix = None tr_classes = [] a_classes = [] if res.is_collection: tr_classes.append("directory") if not is_readonly and not res.is_collection: ext = os.path.splitext(href)[1].lstrip(".").lower() officeType = msOfficeExtToTypeMap.get(ext) if officeType: if self.dir_config.get("ms_sharepoint_support"): ofe_prefix = "ms-{}:ofe|u|".format(officeType) a_classes.append("msoffice") # elif self.dir_config.get("ms_sharepoint_plugin"): # a_classes.append("msoffice") # elif self.dir_config.get("ms_sharepoint_urls"): # href = "ms-{}:ofe|u|{}".format(officeType, href) entry = { "href": href, "ofe_prefix": ofe_prefix, "a_class": " ".join(a_classes), "tr_class": " ".join(tr_classes), "display_name": res.get_display_name(), "last_modified": res.get_last_modified(), "is_collection": res.is_collection, "content_length": res.get_content_length(), "display_type": di.get("type"), "display_type_comment": di.get("typeComment"), } dirInfoList.append(entry) # ignore_patterns = self.dir_config.get("ignore", []) if compat.is_basestring(ignore_patterns): ignore_patterns = ignore_patterns.split(",") ignored_list = [] for entry in dirInfoList: # Skip ignore patterns ignore = False for pat in ignore_patterns: if fnmatch(entry["display_name"], pat): ignored_list.append(entry["display_name"]) # _logger.debug("Ignore {}".format(entry["display_name"])) ignore = True break if ignore: continue # last_modified = entry.get("last_modified") if last_modified is None: entry["str_modified"] = "" else: entry["str_modified"] = util.get_rfc1123_time(last_modified) entry["str_size"] = "-" if not entry.get("is_collection"): content_length = entry.get("content_length") if content_length is not None: entry["str_size"] = util.byte_number_string(content_length) rows.append(entry) if ignored_list: _logger.debug( "Dir browser ignored {} entries: {}".format( len(ignored_list), ignored_list ) ) # sort sort = "name" if sort == "name": rows.sort( key=lambda v: "{}{}".format( not v["is_collection"], v["display_name"].lower() ) ) if "wsgidav.auth.user_name" in environ: context.update( { "is_authenticated": True, "user_name": (environ.get("wsgidav.auth.user_name") or "anonymous"), "realm": environ.get("wsgidav.auth.realm"), "user_roles": ", ".join(environ.get("wsgidav.auth.roles") or []), "user_permissions": ", ".join( environ.get("wsgidav.auth.permissions") or [] ), } ) return context