# Path: wsgidav/util.py
# BASE_LOGGER_NAME = "wsgidav"
# PYTHON_VERSION = "{}.{}.{}".format(
#     sys.version_info[0], sys.version_info[1], sys.version_info[2]
# )
#     READ_ALL = True
# MAX_FINITE_TIMEOUT_LIMIT = 10 * 365 * 24 * 60 * 60  # approx 10 years
# _MIME_TYPES = {
#     ".oga": "audio/ogg",
#     ".ogg": "audio/ogg",
#     ".ogv": "video/ogg",
#     ".webm": "video/webm",
#     # https://mailarchive.ietf.org/arch/msg/media-types/DA8UuKX2dyaVxWh-oevy-t3Vg9Q/
#     ".yml": "application/yaml",
#     ".yaml": "application/yaml",
# }
# class NO_DEFAULT:
# class SubAppStartResponse:
# def is_basestring(s):
# def is_bytes(s):
# def is_str(s):
# def to_bytes(s, encoding="utf8"):
# def to_str(s, encoding="utf8"):
# def to_set(val, *, or_none=False, raise_error=False) -> set:
# def get_dict_value(d, key_path, default=NO_DEFAULT):
# def purge_passwords(d, *, in_place=False):
#     def _purge(v):
# def check_tags(tags, known, *, msg=None, raise_error=True, required=False):
# def unicode_to_wsgi(u):
# def wsgi_to_bytes(s):
# def re_encode_wsgi(s: str, *, encoding="utf-8", fallback=False) -> str:
# def get_rfc1123_time(secs=None):
# def get_rfc3339_time(secs=None):
# def get_log_time(secs=None):
# def parse_time_string(timestring):
# def _parse_gmt_time(timestring):
# def init_logging(config):
# def get_module_logger(moduleName, *, default_to_verbose=False):
# def deep_update(d, u):
# def dynamic_import_class(name):
# def dynamic_instantiate_class(class_name, options, *, expand=None, raise_error=True):
#     def _expand(v):
# def dynamic_instantiate_class_from_opts(options, *, expand=None):
# def removeprefix(s: str, prefix: str, ignore_case: bool = False) -> str:
# def save_split(s, sep, maxsplit):
# def pop_path(path):
# def pop_path2(path):
# def shift_path(script_name, path_info):
# def split_namespace(clark_name):
# def to_unicode_safe(s):
# def safe_re_encode(s, encoding_to, *, errors="backslashreplace"):
# def string_repr(s):
# def get_file_extension(path):
# def byte_number_string(
#     number, *, thousands_sep=True, partition=False, base1024=True, append_bytes=True
# ):
# def fix_path(path, root, *, expand_vars=True, must_exist=True, allow_none=True):
# def get_content_length(environ):
# def read_and_discard_input(environ):
# def fail(value, context_info=None, *, src_exception=None, err_condition=None):
#     def __init__(self):
#     def status(self):
#     def response_headers(self):
#     def exc_info(self):
#     def __call__(self, status, response_headers, exc_info=None):
# def join_uri(uri, *segments):
# def get_uri_name(uri: str) -> str:
# def get_uri_parent(uri: str) -> Optional[str]:
# def is_child_uri(parent_uri: str, child_uri: str) -> bool:
# def is_equal_or_child_uri(parent_uri, child_uri):
# def make_complete_url(environ, local_uri=None):
# def update_headers_in_place(target, new_items) -> None:
# def parse_xml_body(environ, *, allow_empty=False):
# def send_status_response(
#     environ, start_response, e, *, add_headers=None, is_head=False
# ):
# def send_multi_status_response(environ, start_response, multistatus_elem):
# def add_property_response(multistatus_elem, href, prop_list):
# def calc_hexdigest(s):
# def calc_base64(s):
# def checked_etag(etag, *, allow_none=False):
# def parse_if_match_header(value):
# def get_file_etag(file_path):
# def obtain_content_ranges(rangetext, filesize):
# def read_timeout_value_header(timeoutvalue):
# def evaluate_http_conditionals(dav_res, last_modified, entitytag, environ):
# def parse_if_header_dict(environ):
# def test_if_header_dict(dav_res, dictIf, fullurl, locktokenlist, entitytag):
# def guess_mime_type(url):


import sys
from abc import ABC, abstractmethod
from hashlib import md5
from wsgidav import util


class BaseDomainController(ABC):
    #: A domain controller MAY list these values as
    #: `environ["wsgidav.auth.permissions"] = (<permission>, ...)`
    known_permissions = ("browse_dir", "delete_resource", "edit_resource")
    #: A DC may list these values as `environ["wsgidav.auth.roles"] = (<role>, ...)`
    known_roles = ("admin", "editor", "reader")

    def __init__(self, wsgidav_app, config):
        self.wsgidav_app = wsgidav_app
        self.config = config

    def __str__(self):
        return "{}()".format(self.__class__.__name__)

    def _calc_realm_from_path_provider(self, path_info, environ):
        """Internal helper for derived classes to implement get_domain_realm()."""
        if environ:
            # Called while in a request:
            # We don't get the share from the path_info here: it was already
            # resolved and stripped by the request_resolver
            dav_provider = environ["wsgidav.provider"]
        else:
            # Called on start-up with the share root URL
            _share, dav_provider = self.wsgidav_app.resolve_provider(path_info)

        if not dav_provider:
            logger.warn(
                "_calc_realm_from_path_provider('{}'): '{}'".format(

# Path: wsgidav/util.py
# BASE_LOGGER_NAME = "wsgidav"
# PYTHON_VERSION = "{}.{}.{}".format(
#     sys.version_info[0], sys.version_info[1], sys.version_info[2]
# )
#     READ_ALL = True
# MAX_FINITE_TIMEOUT_LIMIT = 10 * 365 * 24 * 60 * 60  # approx 10 years
# _MIME_TYPES = {
#     ".oga": "audio/ogg",
#     ".ogg": "audio/ogg",
#     ".ogv": "video/ogg",
#     ".webm": "video/webm",
#     # https://mailarchive.ietf.org/arch/msg/media-types/DA8UuKX2dyaVxWh-oevy-t3Vg9Q/
#     ".yml": "application/yaml",
#     ".yaml": "application/yaml",
# }
# class NO_DEFAULT:
# class SubAppStartResponse:
# def is_basestring(s):
# def is_bytes(s):
# def is_str(s):
# def to_bytes(s, encoding="utf8"):
# def to_str(s, encoding="utf8"):
# def to_set(val, *, or_none=False, raise_error=False) -> set:
# def get_dict_value(d, key_path, default=NO_DEFAULT):
# def purge_passwords(d, *, in_place=False):
#     def _purge(v):
# def check_tags(tags, known, *, msg=None, raise_error=True, required=False):
# def unicode_to_wsgi(u):
# def wsgi_to_bytes(s):
# def re_encode_wsgi(s: str, *, encoding="utf-8", fallback=False) -> str:
# def get_rfc1123_time(secs=None):
# def get_rfc3339_time(secs=None):
# def get_log_time(secs=None):
# def parse_time_string(timestring):
# def _parse_gmt_time(timestring):
# def init_logging(config):
# def get_module_logger(moduleName, *, default_to_verbose=False):
# def deep_update(d, u):
# def dynamic_import_class(name):
# def dynamic_instantiate_class(class_name, options, *, expand=None, raise_error=True):
#     def _expand(v):
# def dynamic_instantiate_class_from_opts(options, *, expand=None):
# def removeprefix(s: str, prefix: str, ignore_case: bool = False) -> str:
# def save_split(s, sep, maxsplit):
# def pop_path(path):
# def pop_path2(path):
# def shift_path(script_name, path_info):
# def split_namespace(clark_name):
# def to_unicode_safe(s):
# def safe_re_encode(s, encoding_to, *, errors="backslashreplace"):
# def string_repr(s):
# def get_file_extension(path):
# def byte_number_string(
#     number, *, thousands_sep=True, partition=False, base1024=True, append_bytes=True
# ):
# def fix_path(path, root, *, expand_vars=True, must_exist=True, allow_none=True):
# def get_content_length(environ):
# def read_and_discard_input(environ):
# def fail(value, context_info=None, *, src_exception=None, err_condition=None):
#     def __init__(self):
#     def status(self):
#     def response_headers(self):
#     def exc_info(self):
#     def __call__(self, status, response_headers, exc_info=None):
# def join_uri(uri, *segments):
# def get_uri_name(uri: str) -> str:
# def get_uri_parent(uri: str) -> Optional[str]:
# def is_child_uri(parent_uri: str, child_uri: str) -> bool:
# def is_equal_or_child_uri(parent_uri, child_uri):
# def make_complete_url(environ, local_uri=None):
# def update_headers_in_place(target, new_items) -> None:
# def parse_xml_body(environ, *, allow_empty=False):
# def send_status_response(
#     environ, start_response, e, *, add_headers=None, is_head=False
# ):
# def send_multi_status_response(environ, start_response, multistatus_elem):
# def add_property_response(multistatus_elem, href, prop_list):
# def calc_hexdigest(s):
# def calc_base64(s):
# def checked_etag(etag, *, allow_none=False):
# def parse_if_match_header(value):
# def get_file_etag(file_path):
# def obtain_content_ranges(rangetext, filesize):
# def read_timeout_value_header(timeoutvalue):
# def evaluate_http_conditionals(dav_res, last_modified, entitytag, environ):
# def parse_if_header_dict(environ):
# def test_if_header_dict(dav_res, dictIf, fullurl, locktokenlist, entitytag):
# def guess_mime_type(url):


# Path: wsgidav/dc/base_dc.py
import sys
from abc import ABC, abstractmethod
from hashlib import md5
from wsgidav import util



class BaseDomainController(ABC):
    #: A domain controller MAY list these values as
    #: `environ["wsgidav.auth.permissions"] = (<permission>, ...)`
    known_permissions = ("browse_dir", "delete_resource", "edit_resource")
    #: A DC may list these values as `environ["wsgidav.auth.roles"] = (<role>, ...)`
    known_roles = ("admin", "editor", "reader")

    def __init__(self, wsgidav_app, config):
        self.wsgidav_app = wsgidav_app
        self.config = config

    def __str__(self):
        return "{}()".format(self.__class__.__name__)

    def _calc_realm_from_path_provider(self, path_info, environ):
        """Internal helper for derived classes to implement get_domain_realm()."""
        if environ:
            # Called while in a request:
            # We don't get the share from the path_info here: it was already
            # resolved and stripped by the request_resolver
            dav_provider = environ["wsgidav.provider"]
        else:
            # Called on start-up with the share root URL
            _share, dav_provider = self.wsgidav_app.resolve_provider(path_info)

        if not dav_provider:
            logger.warn(
                "_calc_realm_from_path_provider('{}'): '{}'".format(

                    util.safe_re_encode(path_info, sys.stdout.encoding), None