Ë
    "ïàj´ô  ã            	       ó°  — d Z ddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddlmZ ddlmZmZ ddlmZ ddlmZ ddlmZmZmZmZ ddlmZ dd	lmZ dd
l m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z* ddl+m,Z,m-Z-m.Z.m/Z/m0Z0 dZ1dZ2 ejf                  e2«      Z4djk                  ejl                  dd D � cg c]
  }  e7| «      ‘Œ c} «      Z8 ejr                  «       Z:de› �Z;de8› �Z< G d„ d«      Z=dee7   de>fd„Z?d„ Z@d„ ZAd„ ZBdd„ZCdd„ZDdddœdeEfd„ZFe=fddœd „ZGdd!œd"„ZHdd#dd$œd%„ZId&„ ZJd'„ ZKd(dd)œd*e7de7fd+„ZLd€d,„ZMd€d-„ZNd€d.„ZOd/„ ZPd0„ ZQd1„ ZRdd2œd3„ZSd4„ ZTd5„ ZUdd#d6œd7„ZVdd8œd9„ZWd�d*e7d:e7d;e>de7fd<„ZXd=„ ZYd>„ ZZd?„ Z[d@„ Z\dA„ Z]dB„ Z^dC„ Z_dDdEœdF„Z`dG„ ZadH„ Zbd#dd#d#dIœdJ„Zcd#d#d#dKœdL„ZddM„ ZedN„ Zf	 d€dddd#dOœdP„Zg G dQ„ dR«      ZhdS„ ZidTe7de7fdU„ZjdTe7dee7   fdV„ZkdWe7dXe7de>fdY„ZldZ„ Zmd€d[„Znd‚d\„Zodd]œd^„Zpd_„ Zqddd`œda„Zrdb„ Zsdc„ Ztdd„ Zude„ Zvddfœdg„Zwdh„ Zxdi„ Zy e	jô                  dj«      Z{ e	jô                  dk«      Z|dl„ Z}dmZ~ e	jô                  dne	jþ                  «      Z€do„ Z�dp„ Z‚ e	jô                  dq«      Zƒ e	jô                  dr«      Z„ e	jô                  ds«      Z… e	jô                  dt«      Z†du„ Z‡dv„ Zˆdwdwdxdydzdzd{œZ‰d€d|e7d}ee   de7fd~„ZŠyc c} w )ƒz.
Miscellaneous support functions for WsgiDAV.
é    N)Údeepcopy)Ú
formatdateÚ	parsedate)Úmd5)Úpformat)ÚDictÚIterableÚOptionalÚTuple)Úquote)Ú__version__)
ÚHTTP_BAD_REQUESTÚHTTP_CREATEDÚHTTP_NO_CONTENTÚHTTP_NOT_MODIFIEDÚHTTP_OKÚHTTP_PRECONDITION_FAILEDÚHTTP_RANGE_NOT_SATISFIABLEÚDAVErrorÚas_DAVErrorÚget_http_status_string)ÚetreeÚis_etree_elementÚmake_sub_elementÚuse_lxmlÚxml_to_bytesÚreStructuredTextÚwsgidavú.é   zWsgiDAV/zPython/c                   ó   — e Zd ZdZy)Ú
NO_DEFAULTÚ N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__© ó    ú;/srv/dav/.venv/lib/python3.12/site-packages/wsgidav/util.pyr"   r"   E   s   „ Ú
r)   r"   Úmin_versionÚreturnc                 óÚ   — t         j                  | k  rSdj                  | dd D �cg c]  }t        |«      ‘Œ c}«      }t	        j
                  d|› dt        › d�t        d¬«       y	y
c c}w )z$Check for deprecated Python version.r   Nr    z&Support for Python version less than `z` is deprecated (using ú)é   )Ú
stacklevelFT)ÚsysÚversion_infoÚjoinÚstrÚwarningsÚwarnÚPYTHON_VERSIONÚDeprecationWarning)r+   ÚsÚmin_vers      r*   Úcheck_python_versionr;   I   sk   € ä
×Ñ˜+Ò%Ø—(‘(¨K¸¸¨OÖ< qœC �FÒ<Ó=ˆÜ�‰Ø4°W°Ið >Ü$Ð% Qð(äØõ		
ð Øùò =s   ¦A(c                 ó.   — t        | t        t        f«      S )zNReturn True for any string type (for str/unicode on Py2 and bytes/str on Py3).)Ú
isinstancer4   Úbytes©r9   s    r*   Úis_basestringr@   \   s   € ä�aœ#œu˜Ó&Ð&r)   c                 ó"   — t        | t        «      S )z>Return True for bytestrings (for str on Py2 and bytes on Py3).)r=   r>   r?   s    r*   Úis_bytesrB   a   s   € ä�aœÓÐr)   c                 ó"   — t        | t        «      S )z8Return True for native strings (for str on Py2 and Py3).)r=   r4   r?   s    r*   Úis_strrD   f   s   € ä�aœÓÐr)   c                 ó@   — t        | «      t        urt        | |«      } | S )zLConvert a text string (unicode) to bytestring (str on Py2 and bytes on Py3).)Útyper>   ©r9   Úencodings     r*   Úto_bytesrI   k   s   € äˆAƒw”eÑÜ�!�XÓˆØ€Hr)   c                 ó|   — t        | «      t        u rt        | |«      } | S t        | «      t        urt        | «      } | S )zGConvert data to native str type (bytestring on Py2 and unicode on Py3).)rF   r>   r4   rG   s     r*   Úto_strrK   r   s=   € äˆAƒw”%ÑÜ��8Óˆð €Hô 
ˆa‹œÑ	Ü�‹FˆØ€Hr)   F)Úor_noneÚraise_errorc                ó€  — t        «       }t        | «      t         u r| }|S t        | «      t        u r4t        t        t        j                  | j                  d«      «      «      }|S t        | t        t        t        f«      rt        t        t        | «      «      }|S | €|rd }|S |rt        | › dt        | «      › �«      ‚|S )Nú,ú, )ÚsetrF   r4   ÚmapÚstripÚsplitr=   ÚdictÚlistÚtupleÚ	TypeError)ÚvalrL   rM   Úress       r*   Úto_setr[   {   s¶   € Ü
‹%€CÜˆCƒy”CÑØˆð €Jô 
ˆc‹”cÑ	Ü”#”c—i‘i §¡¨3£Ó0Ó1ˆð €Jô 
�Cœ$¤¤eÐ,Ô	-Ü”#”c˜3“-Ó ˆð
 €Jð	 
ˆ™Øˆð €Jñ 
Ü˜3˜%˜r¤$ s£) Ð-Ó.Ð.Ø€Jr)   )Úas_dictc                ól  — |r	 t        | |i ¬«      }|�|S i S |t
        ur	 t        | |«      S |j                  d«      }|j                  d«      }| |   }|rŽ|j                  d«      }t        |t        «      r||   }ndt        |t        t        f«      rA|j                  d«      r|j                  d«      st        d«      ‚|dd }|t        |«         }n	 t        ||«      }|rŒŽ|S # t        t        t        t        f$ r i cY S w xY w# t        t        t        t        f$ r |cY S w xY w# t        $ r ‚ w xY w)	a2  Return the value of a nested dict using dot-notation path.

    Args:
        d (dict):
        key_path (str):
        default  (any):
        as_dict (bool):
            Assume default is `{}` and also return `{}` if the key exists with
            a value of `None`. This covers the case where suboptions are
            supposed to be dicts, but are defined in a YAML file as entry
            without a value.

    Raises:
        KeyError:
        ValueError:
        IndexError:

    Examples::

        ...

    Todo:
        * k[1] instead of k.[1]
    )Údefaultr   r   ú[ú]z(Use `[INT]` syntax to address list itemsé   éÿÿÿÿ)Úget_dict_valueÚAttributeErrorÚKeyErrorÚ
ValueErrorÚ
IndexErrorr"   rT   Úpopr=   rU   rV   rW   Ú
startswithÚendswithÚintÚgetattr)ÚdÚkey_pathr^   r\   rZ   Úseg_listÚsegÚvalues           r*   rc   rc   Š   sD  € ñ2 ð	Ü   H°bÔ9ˆCØ˜/�3Ð1¨rÐ1ð ”jÑ ð	Ü! ! XÓ.Ð.ð �~‰~˜cÓ"€HØ
�,‰,�q‹/€CØˆc‰F€Eá
Ø�l‰l˜1‹oˆÜ�eœTÔ"Ø˜#‘J‰EÜ˜¤¤e˜}Ô-Ø—>‘> #Ô&¨c¯l©l¸3Ô.?Ü Ð!KÓLÐLØ�a˜�)ˆCØœ#˜c›(‘O‰EðÜ  sÓ+�ò ð  €Løô; ¤¬*´jÐAò 	ØŠIð	ûô ¤¬*´jÐAò 	ØŠNð	ûô( "ò Øðús3   „C& –C& ¡D ÃD( Ã&DÄDÄD%Ä$D%Ä(D3)Úin_placec                ól   ‡— ˆfd„Š|st        | «      } | j                  «       D ]
  } ‰|«       Œ |ry | S )Nc                 óÖ   •— t        | t        «      r'd| v rd| d<   | j                  «       D ]
  } ‰|«       Œ y t        | t        «      r!t        | t        «      s| D ]
  } ‰|«       Œ y y y )NÚpasswordz	<REMOVED>)r=   rU   Úvaluesr	   r4   )ÚvÚeleÚ_purges     €r*   ry   zpurge_passwords.<locals>._purgeË   sk   ø€ Ü�aœÔØ˜Q‰Ø +��*‘Ø—x‘x“zò �Ù�s•ñä˜œ8Ô$¬Z¸¼3Ô-?Øò �Ù�s•ñð .@Ð$r)   )r   rv   )rm   rr   rw   ry   s      @r*   Úpurge_passwordsrz   Ê   s?   ø€ ôñ Ü�Q‹Kˆà�X‰X‹Zò ˆÙˆq�	ðñ ØØ€Hr)   T)ÚmsgrM   Úrequiredc                ó�  — |sJ d«       ‚t        |«      }|}|du r|}t        «       }n/|r-t        |«      }|j                  |«      }|j                  |«      }t        | «      } g }| j                  |«      }|r/|j	                  dj                  dj                  |«      «      «       |rB|j                  | «      }|r/|j	                  dj                  dj                  |«      «      «       |rÛ|r|j                  d|«       |rB|r@|j	                  dj                  dj                  |«      dj                  |«      «      «       nc|r0|j	                  dj                  dj                  |«      «      «       n1|r/|j	                  d	j                  dj                  |«      «      «       d
j                  |«      }|rt        |«      ‚|S y)zšCheck if `tags` only contains known tags.

    If check fails and raise_error is true, a ValueError is raised.
    If check passes, None is returned.
    zmust not be emptyTzUnknown: {!r}z', 'zMissing: {!r}r   z"Required: ({!r}). Optional: ({!r})zRequired: ({!r})zOptional: ({!r})ú
N)	r[   rQ   ÚunionÚ
differenceÚappendÚformatr3   Úinsertrf   )	ÚtagsÚknownr{   rM   r|   ÚoptionalrZ   ÚunknownÚmissings	            r*   Ú
check_tagsr‰   à   sŠ  € ñ Ð%Ð%Ó%ˆ5Ü�5‹M€EØ€Hà�4ÑØˆÜ“5‰Ù	Ü˜(Ó#ˆØ—‘˜HÓ%ˆØ×#Ñ# HÓ-ˆä�$‹<€Dà
€CØ�o‰o˜eÓ$€GÙØ�
‰
�?×)Ñ)¨&¯+©+°gÓ*>Ó?Ô@áØ×%Ñ% dÓ+ˆÙØ�J‰J�×-Ñ-¨f¯k©k¸'Ó.BÓCÔDá
ÙØ�J‰J�q˜#Ôá™Ø�J‰JØ4×;Ñ;Ø—K‘K Ó)¨6¯;©;°xÓ+@óõñ
 Ø�J‰JÐ)×0Ñ0°·±¸XÓ1FÓGÕHÙØ�J‰JÐ)×0Ñ0°·±¸XÓ1FÓGÔHà�i‰i˜‹nˆÙÜ˜S“/Ð!Øˆ
àr)   c                 óL   — | j                  t        d«      j                  d«      S )zDConvert an environment variable to a WSGI 'bytes-as-unicode' string.Úsurrogateescapeú
iso-8859-1)ÚencodeÚfilesystemencodingÚdecode)Úus    r*   Úunicode_to_wsgir‘     s"   € ð �8‰8Ô&Ð(9Ó:×AÑAÀ,ÓOÐOr)   c                 ó$   — | j                  d«      S )z¦Convert a native string to a WSGI / HTTP compatible byte string.

    WSGI always assumes iso-8859-1 (PEP 3333).
    https://bugs.python.org/issue16679#msg177450
    rŒ   )r�   r?   s    r*   Úwsgi_to_bytesr“     s   € ð �8‰8�LÓ!Ð!r)   zutf-8)rH   Úfallbackr9   c                ó°   — 	 t        | «      t        u r| j                  |«      S | j                  d«      j                  |«      S # t        $ r |r| cY S ‚ w xY w)a  Convert a WSGI string to `str`, assuming the client used UTF-8.

    WSGI always assumes iso-8859-1. Modern clients send UTF-8, so we have to
    re-encode

    https://www.python.org/dev/peps/pep-3333/#unicode-issues
    https://bugs.python.org/issue16679#msg177450
    rŒ   )rF   r>   r�   r�   ÚUnicodeDecodeError)r9   rH   r”   s      r*   Úre_encode_wsgir—   (  sV   € ðÜ�‹7”eÑà—8‘8˜HÓ%Ð%Ø�x‰x˜Ó%×,Ñ,¨XÓ6Ð6øÜò ÙØŠHØðús   ‚!A ¤A ÁAÁAc                 ó   — t        | dd¬«      S )zMReturn <secs> in rfc 1123 date/time format (pass secs=None for current date).FT)ÚtimevalÚ	localtimeÚusegmt)r   ©Úsecss    r*   Úget_rfc1123_timerž   A  s   € ô ˜d¨e¸DÔAÐAr)   c                 óT   — t        j                  dt        j                  | «      «      S )zÃReturn <secs> in RFC 3339 date/time format (pass secs=None for current date).

    RFC 3339 is a subset of ISO 8601, used for '{DAV:}creationdate'.
    See http://tools.ietf.org/html/rfc3339
    z%Y-%m-%dT%H:%M:%SZ©ÚtimeÚstrftimeÚgmtimerœ   s    r*   Úget_rfc3339_timer¤   G  s   € ô �=‰=Ð-¬t¯{©{¸4Ó/@ÓAÐAr)   c                 óT   — t        j                  dt        j                  | «      «      S )zCReturn <secs> in log time format (pass secs=None for current date).z%Y-%m-%d %H:%M:%Sr    rœ   s    r*   Úget_log_timer¦   P  s   € ä�=‰=Ð,¬d¯k©k¸$Ó.?Ó@Ð@r)   c                 óH   — t        | «      }|rt        j                  |«      S y)ah  Return the number of seconds since the epoch, for a date/time string.

    Returns None for invalid input

    The following time type strings are supported:

    Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
    Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
    Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
    N)Ú_parse_gmt_timeÚcalendarÚtimegm)Ú
timestringÚresults     r*   Úparse_time_stringr­   U  s#   € ô ˜ZÓ(€FÙÜ�‰˜vÓ&Ð&Ør)   c                 ó  — 	 t        j                  | d«      S # t        $ r Y nw xY w	 t        j                  | d«      S # t        $ r Y nw xY w	 t        j                  | d«      S # t        $ r Y nw xY w	 t        | «      S # t        $ r Y yw xY w)zMReturn a standard time tuple (see time and calendar), for a date/time string.z%a, %d %b %Y %H:%M:%S GMTz%A %d-%b-%y %H:%M:%S GMTz%a %b %d %H:%M:%S %YN)r¡   ÚstrptimeÚ	Exceptionr   )r«   s    r*   r¨   r¨   f  s¢   € ðÜ�}‰}˜ZÐ)DÓEÐEøÜò ÙðúðÜ�}‰}˜ZÐ)CÓDÐDøÜò ÙðúðÜ�}‰}˜ZÐ)?Ó@Ð@øÜò Ùðúð
Ü˜Ó$Ð$øÜò Øàðús?   ‚ ˜	$£$¨> ¾	A
Á	A
ÁA$ Á$	A0Á/A0Á4
A? Á?	BÂ
Bc                 óÀ  — ddl m}m} | j                  dd«      }| j                  d«      xs i }|j                  dg «      }|€g }|j                  d|«      }|j                  d	|«      }t	        j
                  ||«      }t	        j                  t        j                  «      }	|	j                  |«       t	        j                  t        «      }
|d
k\  r |
j                  t        j                  «       nŽ|dk(  r |
j                  t        j                  «       ni|dk(  r |
j                  t        j                  «       nD|dk(  r |
j                  t        j                   «       n|
j                  t        j"                  «       d|
_        |
j&                  dd D ]4  }	 |j)                  «        |j+                  «        |
j/                  |«       Œ6 |
j1                  |	«       |dk\  rm|D ]h  }|j3                  t        dz   «      st        dz   |z   }t	        j                  |j5                  «       «      }|j                  t        j                  «       Œj y# t,        $ r Y Œ¢w xY w)aà
  Initialize base logger named 'wsgidav'.

    The base logger is filtered by the `verbose` configuration option.
    Log entries will have a time stamp and thread id.

    **Note:** init_logging() is automatically called if an application adds
    ``"logging": { "enable": true }`` to the configuration.

    Module loggers
    ~~~~~~~~~~~~~~
    Module loggers (e.g 'wsgidav.lock_man.lock_manager') are named loggers, that
    can be independently switched to DEBUG mode.

    Except for verbosity, they will inherit settings from the base logger.

    They will suppress DEBUG level messages, unless they are enabled by passing
    their name to util.init_logging().

    If enabled, module loggers will print DEBUG messages, even if verbose == 3.

    Example initialize and use a module logger, that will generate output,
    if enabled (and verbose >= 2)::

        _logger = util.get_module_logger(__name__)
        [..]
        _logger.debug("foo: {!r}".format(s))

    This logger would be enabled by passing its name to init_logging()::

        config.logging.enable_loggers = ["lock_manager",
                          "property_manager",
                         ]
        util.init_logging(2, enable_loggers)


    Log Level Matrix
    ~~~~~~~~~~~~~~~~

    +---------+--------+---------------------------------------------------------------+
    | Verbose | Option |                       Log level                               |
    | level   |        +-------------+------------------------+------------------------+
    |         |        | base logger | module logger(default) | module logger(enabled) |
    +=========+========+=============+========================+========================+
    |    0    | -qqq   | CRITICAL    | CRITICAL               | CRITICAL               |
    +---------+--------+-------------+------------------------+------------------------+
    |    1    | -qq    | ERROR       | ERROR                  | ERROR                  |
    +---------+--------+-------------+------------------------+------------------------+
    |    2    | -q     | WARN        | WARN                   | WARN                   |
    +---------+--------+-------------+------------------------+------------------------+
    |    3    |        | INFO        | INFO                   | **DEBUG**              |
    +---------+--------+-------------+------------------------+------------------------+
    |    4    | -v     | DEBUG       | DEBUG                  | DEBUG                  |
    +---------+--------+-------------+------------------------+------------------------+
    |    5    | -vv    | DEBUG       | DEBUG                  | DEBUG                  |
    +---------+--------+-------------+------------------------+------------------------+

    r   )ÚDEFAULT_LOGGER_DATE_FORMATÚDEFAULT_LOGGER_FORMATÚverboser    ÚloggingÚenable_loggersNÚlogger_date_formatÚlogger_formaté   r/   ra   Fr   )Úwsgidav.default_confr²   r³   Úgetrµ   Ú	FormatterÚStreamHandlerr1   ÚstdoutÚsetFormatterÚ	getLoggerÚBASE_LOGGER_NAMEÚsetLevelÚDEBUGÚINFOÚWARNÚERRORÚCRITICALÚ	propagateÚhandlersÚflushÚcloser°   ÚremoveHandlerÚ
addHandlerri   rS   )Úconfigr²   r³   r´   Úlog_optsr¶   r·   r¸   Ú	formatterÚconsoleHandlerÚloggerÚhdlrÚeÚlgs                 r*   Úinit_loggingrÖ   ‰  sù  € ÷t Wà�j‰j˜ AÓ&€GØ�z‰z˜)Ó$Ò*¨€Hà—\‘\Ð"2°BÓ7€NØÐØˆà!Ÿ™Ð&:Ð<VÓWÐØ—L‘L Ð2GÓH€Mô ×!Ñ! -Ð1CÓD€Iô ×*Ñ*¬3¯:©:Ó6€Nà×Ñ 	Ô*ô ×ÑÔ/Ó0€Fà�!‚|Ø�‰œŸ™Õ&Ø	�AŠØ�‰œŸ™Õ%Ø	�AŠØ�‰œŸ™Õ%à	�AŠØ�‰œŸ™Õ&ð 	�‰œ×(Ñ(Ô)ð €FÔð —‘¡Ð"ò #ˆð	Ø�J‰JŒLØ�J‰JŒLð 	×Ñ˜TÕ"ð#ð ×Ñ�nÔ%à�!‚|Øò 	'ˆAØ—<‘<Ô 0°3Ñ 6Ô7Ü$ sÑ*¨QÑ.�Ü×"Ñ" 1§7¡7£9Ó-ˆBØ�K‰KœŸ™Õ&ð		'ð
 øô ò 	Ùð	ús   Æ IÉ	IÉI)Údefault_to_verbosec                óx   — | j                  t        dz   «      st        dz   | z   } t        j                  | «      }|S )zcCreate a module logger, that can be en/disabled by configuration.

    @see: unit.init_logging
    r   )ri   rÁ   rµ   rÀ   )Ú
moduleNamer×   rÒ   s      r*   Úget_module_loggerrÚ     s>   € ð × Ñ Ô!1°CÑ!7Ô8Ü%¨Ñ+¨jÑ8ˆ
Ü×Ñ˜zÓ*€Fð €Mr)   c                 óX  — |j                  «       D ]–  \  }}t        |t        j                  j                  «      rh| j                  |«      }|�!t        |«      t        t        t        t        fv r|j                  «       | |<   Œrt        | j                  |i «      |«      | |<   Œ’|| |<   Œ˜ | S ©N)Úitemsr=   ÚcollectionsÚabcÚMappingr»   rF   ÚboolÚfloatrk   r4   ÚcopyÚdeep_update)rm   r�   Úkrw   Úprev_vals        r*   rä   rä     s‘   € à—‘“	ò ‰ˆˆ1Ü�aœŸ™×0Ñ0Ô1à—u‘u˜Q“xˆHàÐ¤4¨£>´d¼EÄ3ÌÐ5LÑ#Là—v‘v“x��!’ô # 1§5¡5¨¨B£<°Ó3��!’àˆAˆaŠDðð €Hr)   c                 óò   — ddl }d| vrt        d| ›�«      ‚| j                  dd«      \  }}	 |j                  |«      }t        ||«      }|S # t        $ r!}t
        j                  d| ›d|› �«       ‚ d}~ww xY w)zBImport a class from a module string, e.g. ``my.module.ClassName``.r   Nr   z%Expected `path.to.ClassName` string: ra   zDynamic import of z	 failed: )Ú	importlibrf   ÚrsplitÚimport_moduler°   Ú_loggerÚerrorrl   )Únamerè   Úmodule_nameÚ
class_nameÚmodulerÔ   Ú	the_classs          r*   Údynamic_import_classrò   *  sŒ   € ãà
�$�ÜÐ@ÀÀÐIÓJÐJØ"Ÿk™k¨#¨qÓ1Ñ€K�ðØ×(Ñ(¨Ó5ˆô ˜ 
Ó+€IØÐøô	 ò Ü�‰Ð*¨4¨(°)¸A¸3Ð?Ô@Øûðús   ­A Á	A6ÁA1Á1A6)ÚexpandrM   c                óL  ‡— ˆfd„}t        |ddhd| › �¬«       |j                  d«      xs g }|�$t        |t        t        f«      st        d|› �«      ‚|j                  d«      xs i }|�t        |t        «      st        d|› �«      ‚	 d}t        | «      }t        t        ||«      «      }|j                  «       D �	�
ci c]  \  }	}
|	 ||
«      “Œ }}	}
 ||i |¤Ž}|D �cg c]  }|› ‘Œ c}|j                  «       D �	�
cg c]  \  }	}
|	› d	|
›�‘Œ c}
}	z   }t        j                  d
j                  | dj                  |«      |«      «       |S c c}
}	w c c}w c c}
}	w # t        $ r: d| › d|› d�}|rt        j                  |«       ‚ t        j!                  |«       Y S w xY w)a‹  Import a class and instantiate with custom args.

    Equivalent of
    ```py
    from my.module import Foo
    return Foo(bar=42, baz="qux")
    ```
    would be
    ```py
    options = {
        "bar": 42,
        "baz": "qux"
    }
    =>
    ```
    Examples:
        # Equivalent of
        name = "my.module.Foo"
        from my.module import Foo
        return Foo(bar=42, baz="qux")
    c                 óP   •— ‰r"t        | «      r| j                  «       ‰v r‰|    S | S )z2Replace some string templates with defined values.)r@   Úlower)rw   ró   s    €r*   Ú_expandz*dynamic_instantiate_class.<locals>._expandQ  s)   ø€ á”m AÔ&¨1¯7©7«9¸Ñ+>Ø˜!‘9ÐØˆr)   ÚargsÚkwargsz(Invalid class instantiation options for )r{   Nz(Expected list format for `args` option: z*Expected dict format for `kwargs` option: ú=zInstantiate {}({}) => {}rP   zInstantiate ú(z) failed)r‰   r»   r=   rW   rV   rf   rU   rò   rR   rÝ   rë   Údebugr‚   r3   r°   rì   Ú	exception)rï   Úoptionsró   rM   r÷   Úpos_argsrù   Úinstrñ   rå   rw   ÚoÚ	disp_argsr{   s     `           r*   Údynamic_instantiate_classr  :  s¼  ø€ ô.ô ØØ	�ÐØ6°z°lÐCõð
 �{‰{˜6Ó"Ò( b€HØÐ¤J¨x¼%Ä¸Ô$GÜÐCÀGÀ9ÐMÓNÐNà�[‰[˜Ó"Ò( b€FØÐ¤*¨V´TÔ":ÜÐEÀgÀYÐOÓPÐPðØˆÜ(¨Ó4ˆ	Üœ˜W hÓ/Ó0ˆØ,2¯L©L«N×;¡D A q�!‘W˜Q“Z‘-Ð;ˆÑ;ñ ˜(Ð- fÑ-ˆà%-Ö. ˜�s‘VÒ.Ø%+§\¡\£^÷2
Ù!˜Q ˆqˆc��1�%ŠLó2
ñ 
ˆ	ô 	�‰Ø&×-Ñ-¨j¸$¿)¹)ÀIÓ:NÐPTÓUô	
ð €Kùó3 <ùò /ùó 2
øô ò Ø˜Z˜L¨¨'¨°(Ð;ˆÙÜ�M‰M˜#ÔØÜ×Ñ˜#Õà€Kðús<   Â5E  Ã EÃE  Ã"
EÃ,E  ÄEÄ;E  ÅE  Å ?F#Æ"F#©ró   c                ó®   — t        | «      t        u rd| i} n| j                  «       } t        | h d£dd¬«       | j	                  d«      }t        || |¬«      S )a÷  Import a class and instantiate with custom args.


    Construct from class path, without constructor args:
    ```py
    dynamic_instantiate_class_from_opts("wsgidav.lock_man.lock_storage.LockStorageDict")
    ```
    Construct with constructor args:
    ```py
    opts = {
        "class": "wsgidav.lock_man.lock_storage.LockStorageShelve",
        "kwargs": {
            "storage_path": "~/wsgidav_locks.shelve",
        }
    }
    dynamic_instantiate_class_from_opts(opts, expand=...)
    ```
    Úclass>   rø   r  rù   z#Invalid class instantiation options)r|   r{   r  )rF   r4   rã   r‰   rh   r  )rþ   ró   rï   s      r*   Ú#dynamic_instantiate_class_from_optsr  „  sX   € ô& ˆGƒ}œÑØ˜GÐ$‰à—,‘,“.ˆäØÚ#ØØ1õ	ð —‘˜WÓ%€JÜ$ Z°ÀÔHÐHr)   ÚprefixÚignore_casec                 ó¦   — |r/| j                  «       j                  |j                  «       «      s| S | j                  |«      s| S | t        |«      d S )zDReplacement for str.removeprefix() (Py3.9+) with ignore_case option.N)rö   ri   Úlen)r9   r  r	  s      r*   Úremoveprefixr  «  sF   € áØ�w‰w‹y×#Ñ# F§L¡L£NÔ3ØˆHà�|‰|˜FÔ#ØˆHØŒS�‹[ˆ]ÐÐr)   c                 ó†   — | j                  ||«      }t        |«      |k  r |j                  d«       t        |«      |k  rŒ |S )zGSplit string, always returning n-tuple (filled with None if necessary).N)rT   r  r�   )r9   ÚsepÚmaxsplitÚtoks       r*   Ú
save_splitr  ¶  s=   € à
�'‰'�#�xÓ
 €CÜ
ˆc‹(�hÒ
Ø�
‰
�4Ôô ˆc‹(�hÓ
à€Jr)   c                 óˆ   — | dv ry| j                  d«      sJ ‚| j                  d«      j                  d«      \  }}}|d|z   fS )z!Return '/a/b/c' -> ('a', '/b/c').©r#   ú/)r#   r#   r  )ri   ÚlstripÚ	partition)ÚpathÚfirstÚ_sepÚrests       r*   Úpop_pathr  ¾  sN   € àˆyÑØØ�?‰?˜3ÔÐÐØŸ™ CÓ(×2Ñ2°3Ó7Ñ€Eˆ4�Ø�3˜‘:ÐÐr)   c                 ó  — g }| j                  d«      D ]C  }|dv rŒ|dk(  r&|r|j                  «        Œ t        t        d| › �«      ‚|j	                  |«       ŒE t        j                  dg|¢­Ž }| j                  d«      r
|dk7  r|dz  }|S )zAReturn the canonical URL path used for routing and authorization.r  )r#   r   z..zPath escapes application root: )rT   rh   r   r   r�   Ú	posixpathr3   rj   )r  ÚpartsÚpartÚ
normalizeds       r*   Únormalize_pathr!  Ç  sœ   € à€EØ—
‘
˜3“ò ˆØ�9ÑØØ�4Š<ÙØ—	‘	•äÜ$Ð(GÈÀvÐ&Nóð ð �L‰L˜Õðô —‘ Ð, eÒ,€JØ‡}�}�SÔ˜j¨CÒ/Ø�cÑˆ
ØÐr)   c                 óT   — | dv ryt        | «      \  }}t        |«      \  }}||d|z   fS )z$Return '/a/b/c' -> ('a', 'b', '/c').r  )r#   r#   r#   r  )r  )r  r  r  Úseconds       r*   Ú	pop_path2r$  Ý  s8   € àˆyÑØÜ˜4“.�K€Eˆ4Ü˜D“>�L€FˆDØ�6˜3 ™:Ð&Ð&r)   c                 óx   — t        |«      \  }}|t        | j                  d«      |«      |j                  d«      fS )z,Return ('/a', '/b/c') -> ('b', '/a/b', 'c').r  )r  Újoin_uriÚrstrip)Úscript_nameÚ	path_infoÚsegmentr  s       r*   Ú
shift_pathr+  æ  s8   € ä˜YÓ'�M€GˆTØ”X˜k×0Ñ0°Ó5°wÓ?ÀÇÁÈSÓAQÐRÐRr)   c                 ól   — | j                  d«      r d| v r| j                  dd«      \  }}|dd |fS d| fS )z¹Return (namespace, localname) tuple for a property name in Clark Notation.

    Namespace defaults to ''.
    Example:
    '{DAV:}foo'  -> ('DAV:', 'foo')
    'bar'  -> ('', 'bar')
    ú{ú}ra   Nr#   )ri   rT   )Ú
clark_nameÚnsÚ	localnames      r*   Úsplit_namespacer2  ì  sK   € ð ×Ñ˜SÔ! c¨ZÑ&7Ø"×(Ñ(¨¨aÓ0‰ˆˆIØ�1�2�˜	Ð"Ð"Ø�
ÐÐr)   c                 óŠ   — 	 t        | d«      }|S # t        $ r) t        j                  d| ›d�«       t        | d«      }Y |S w xY w)zHConvert a binary string to Unicode using UTF-8 (fallback to ISO-8859-1).Úutf8zto_unicode_safe(z%) *** UTF-8 failed. Trying ISO-8859-1z
ISO-8859-1)rK   rf   rë   rì   )r9   r�   s     r*   Úto_unicode_safer5  ú  sS   € ð$Ü�1�fÓˆð €Høô ò $Ü�‰Ð(¨¨Ð-RÐSÔTÜ�1�lÓ#‰Ø€Hð$ús   ‚ �.AÁAÚbackslashreplace©Úerrorsc                ó°   — |sd}t        | «      r$| j                  ||¬«      j                  |«      } | S | j                  ||¬«      j                  |«      } | S )u)  Re-encode str or binary so that is compatible with a given encoding (replacing
    unsupported chars).

    We use ASCII as default, which gives us some output that contains Â™ and é¦™
    for every character > 127, for easier debugging.
    (e.g. if we don't know the encoding, see #87, #96)
    ÚASCIIr7  )rB   r�   r�   )r9   Úencoding_tor8  s      r*   Úsafe_re_encoder<    s[   € ñ ØˆÜ�„{Ø�H‰H�[¨ˆHÓ0×7Ñ7¸ÓDˆð €Hð �H‰H�[¨ˆHÓ0×7Ñ7¸ÓDˆà€Hr)   c                 ó‚   — t        | «      r2| ›d�}| D ]&  }t        |«      t        u rt        |«      }|d|z  z  }Œ( |S | › S )zReturn a string as hex dump.z: z%02x )rB   rF   r4   Úord)r9   rZ   Úbs      r*   Ústring_reprr@    sS   € ä�„{Ø��RˆjˆØò 	ˆAÜ�A‹wœ#‰~Ü˜“F�Ø�7˜Q‘;Ñ‰Cð	ð ˆ
ØˆS€Mr)   c                 óJ   — t         j                  j                  | «      d   }|S )Nra   )Úosr  Úsplitext)r  Úexts     r*   Úget_file_extensionrE  #  s    € Ü
�'‰'×
Ñ
˜4Ó
  Ñ
#€CØ€Jr)   )Úthousands_sepr  Úbase1024Úappend_bytesc                óÔ   — d}d}|r6d}|r| dk\  r&|dz  }| dz	  } | dk\  rŒn| dk\  r|dz  }| dz  } | dk\  rŒg d¢|   }|r
| dk(  rd	}nd
}|r| dk\  s|r| d›}nt        | «      }|› |› |› �S )z1Convert bytes into human-readable representation.r#   r   i   ra   é
   iè  g     @�@)r#   ÚKÚMÚGÚTÚPz Bytez Bytesz,d)r4   )	ÚnumberrF  r  rG  rH  Ú	magsuffixÚ
bytesuffixÚ	magnitudeÚsnums	            r*   Úbyte_number_stringrU  (  s²   € ð €IØ€JáØˆ	ÙØ˜D’.Ø˜Q‘�	Ø 2™�ð ˜D”.ð ˜D’.Ø˜Q‘�	Ø˜&Ñ �ð ˜D“.ò 2°)Ñ<ˆ	áØ�QŠ;Ø ‰Jà!ˆJá˜& Dš.©Ið ˜�‰ä�6‹{ˆàˆV�I�;˜z˜lÐ+Ð+r)   )Úexpand_varsÚ
must_existÚ
allow_nonec                ó   — | dv r|ryt        d| ›�«      ‚t        j                  j                  | «      s¬|st        j                  «       }nXt        |«      t        u rG|j                  d«      }|r t        j                  j                  |«      }nt        j                  «       }t        j                  j                  t        j                  j                  || «      «      } |r<t        j                  j                  t        j                  j                  | «      «      } |r-t        j                  j                  | «      st        d| ›�«      ‚| S )zœConvert path to absolute, expand and check.

    Convert path to absolute if required, expand leading '~' as user home dir,
    expand %VAR%, $Var, ...
    ©Nr#   NzInvalid path Ú_config_filezInvalid path: )rf   rB  r  ÚisabsÚgetcwdrF   rU   r»   ÚdirnameÚabspathr3   Ú
expandvarsÚ
expanduserÚexists)r  ÚrootrV  rW  rX  Úconfig_files         r*   Úfix_pathre  O  sî   € ð ˆzÑÙØÜ˜=¨¨Ð1Ó2Ð2ä�7‰7�=‰=˜ÔÙÜ—9‘9“;‰DÜ�$‹Zœ4ÑàŸ(™( >Ó2ˆKÙÜ—w‘w—‘ {Ó3‘ä—y‘y“{�ô �w‰w�‰œrŸw™wŸ|™|¨D°$Ó7Ó8ˆáÜ�w‰w×!Ñ!¤"§'¡'×"4Ñ"4°TÓ":Ó;ˆáœ"Ÿ'™'Ÿ.™.¨Ô.Ü˜>¨$¨Ð2Ó3Ð3à€Kr)   c           	      ól   — 	 t        dt        | j                  dd«      «      «      S # t        $ r Y yw xY w)zDReturn a positive CONTENT_LENGTH in a safe way (return 0 otherwise).r   ÚCONTENT_LENGTH)Úmaxrk   r»   rf   )Úenvirons    r*   Úget_content_lengthrj  u  s7   € ðÜ�1”c˜'Ÿ+™+Ð&6¸Ó:Ó;Ó<Ð<øÜò Ùðús   ‚$' §	3²3c                 óž  — | j                  d«      s| j                  d«      ryt        | «      }|dk\  sJ ‚|dk(  ryd}d| d<   |rd| d<   | d   }t        |d«      rnt        |d	«      rb|j                  dk(  rR|j                  dkD  rB|r|j                  }nd}|j                  |«      }t        j                  d
|› d|dd ›d�«       yyyt        |d«      r�t        |j                  d«      rx	 |j                  }|j                  «       }|j                  d«       	 |r|}nd}|j                  |«      }t        j                  d
|› d|dd ›d�«       |j                  |«       yyy# t        $ r%}t        j                  d› d|› �«       Y d}~Œ=d}~ww xY w# t        $ r- t        j                  dt        j                  «       › �«       Y yw xY w)ao  Read 1 byte from wsgi.input, if this has not been done yet.

    Returning a response without reading from a request body might confuse the
    WebDAV client.
    This may happen, if an exception like '401 Not authorized', or
    '500 Internal error' was raised BEFORE anything was read from the request
    stream.

    See GC issue 13, issue 23
    See http://groups.google.com/group/paste-users/browse_frm/thread/fc0c9476047e9a47?hl=en

    Note that with persistent sessions (HTTP/1.1) we must make sure, that the
    'Connection: closed' header is set with the response, to prevent reusing
    the current stream.
    zwsgidav.some_input_readúwsgidav.all_input_readNr   Tra   ú
wsgi.inputÚ	_consumedÚlengthzReading z= bytes from potentially unread httpserver.LimitedLengthFile: é2   z...Ú_sockÚ
settimeoutz* bytes from potentially unread POST body: z-> read z bytes failed: z--> wsgi_input.read(): )r»   rj  Úhasattrrn  ro  Úreadrë   rü   rq  Ú
gettimeoutrr  ÚOSErrorrì   r°   r1   Úexc_info)	ri  ÚclÚREAD_ALLÚ
wsgi_inputÚnÚbodyÚsockÚtimeoutÚses	            r*   Úread_and_discard_inputr€  ‰  sî  € ð  ‡{�{Ð,Ô-°·±Ð=UÔ1VØÜ	˜GÓ	$€BØ�Š7€Nˆ7Ø	ˆQ‚wØà€Hà)*€GÐ%Ñ&ÙØ,-ˆÐ(Ñ)à˜Ñ&€Jô ˆz˜;Ô'¬G°JÀÔ,Ið
 ×Ñ 1Ò$¨×):Ñ):¸QÒ)>áØ×%Ñ%‘à�Ø—?‘? 1Ó%ˆDÜ�M‰MØ˜1˜#ÐZÐ[_Ð`cÐacÐ[dÐZgÐgjÐkõð *?Ð$ô 
�˜WÔ	%¬'°*×2BÑ2BÀLÔ*Qð	Fà×#Ñ#ˆDØ—o‘oÓ'ˆGØ�O‰O˜AÔðAÙØ‘Aà�AØ!—‘ qÓ)�Ü—‘Ø˜q˜cÐ!KÈDÐQTÐRTÈIÈ=ÐX[Ð\ôð �O‰O˜GÕ$ð+ +RÐ	%øô" ò Aä—‘ ¨¨¨?¸2¸$Ð?×@Ñ@ûðAûô
 ò 	FÜ�M‰MÐ3´C·L±L³NÐ3CÐDÖEð	Fús<   Ã,-F Ä7E% ÅF Å%	FÅ.FÆ	F ÆFÆF Æ3GÇG©Úsrc_exceptionÚerr_conditionÚadd_headersÚadd_bodyc                ó¬   — t        | t        «      rt        | «      }nt        | |||||¬«      }t        j                  d|j                  «       › �«       |‚)z$Wrapper to raise (and log) DAVError.r�  zRaising DAVError )r=   r°   r   r   rë   rü   Úget_user_info)rq   Úcontext_infor‚  rƒ  r„  r…  rÔ   s          r*   Úfailr‰  Ó  sW   € ô �%œÔ#Ü˜Ó‰äØØØ'Ø'Ø#Øô
ˆô ‡M�MÐ% a§o¡oÓ&7Ð%8Ð9Ô:Ø
€Gr)   c                   óV   ‡ — e Zd Zˆ fd„Zed„ «       Zed„ «       Zed„ «       Zdd„Zˆ xZ	S )ÚSubAppStartResponsec                 óL   •— d| _         g | _        d | _        t        ‰| �  «        y rZ  )Ú_SubAppStartResponse__statusÚ&_SubAppStartResponse__response_headersÚ_SubAppStartResponse__exc_infoÚsuperÚ__init__)ÚselfÚ	__class__s    €r*   r‘  zSubAppStartResponse.__init__ð  s$   ø€ ØˆŒØ"$ˆÔØˆŒä‰ÑÕr)   c                 ó   — | j                   S rÜ   )r�  ©r’  s    r*   ÚstatuszSubAppStartResponse.status÷  s   € à�}‰}Ðr)   c                 ó   — | j                   S rÜ   )rŽ  r•  s    r*   Úresponse_headersz$SubAppStartResponse.response_headersû  s   € à×&Ñ&Ð&r)   c                 ó   — | j                   S rÜ   )r�  r•  s    r*   rw  zSubAppStartResponse.exc_infoÿ  s   € à�‰Ðr)   c                 ó.   — || _         || _        || _        y rÜ   )r�  rŽ  r�  )r’  r–  r˜  rw  s       r*   Ú__call__zSubAppStartResponse.__call__  s   € ØˆŒØ"2ˆÔØ"ˆ�r)   rÜ   )
r$   r%   r&   r‘  Úpropertyr–  r˜  rw  r›  Ú__classcell__)r“  s   @r*   r‹  r‹  ï  sI   ø„ ôð ñó ðð ñ'ó ð'ð ñó ð÷#r)   r‹  c                 óZ   — dj                  |«      }|s| S | j                  d«      dz   |z   S )zEAppend segments to URI.

    Example: join_uri("/a/b", "c", "d")
    r  )r3   r'  )ÚuriÚsegmentsÚsubs      r*   r&  r&    s2   € ð
 �(‰(�8Ó
€CÙØˆ
Ø�:‰:�c‹?˜SÑ  3Ñ&Ð&r)   rŸ  c                 óH   — | j                  d«      j                  d«      d   S )z,Return local name, i.e. last segment of URI.r  rb   )rS   rT   ©rŸ  s    r*   Úget_uri_namer¤    s    € à�9‰9�S‹>×Ñ Ó$ RÑ(Ð(r)   c                 ó|   — | r| j                  «       dk(  ry| j                  d«      j                  dd«      d   dz   S )zÏReturn URI of parent collection with trailing '/', or None, if URI is top-level.

    This function simply strips the last segment. It does not test, if the
    target is a 'collection', or even exists.
    r  Nra   r   )rS   r'  ré   r£  s    r*   Úget_uri_parentr¦    s<   € ñ �#—)‘)“+ Ò$ØØ�:‰:�c‹?×!Ñ! # qÓ)¨!Ñ,¨sÑ2Ð2r)   Ú
parent_uriÚ	child_uric                 óš   — t        | «      xr? t        |«      xr2 |j                  d«      j                  | j                  d«      dz   «      S )záReturn True, if child_uri is a child of parent_uri.

    This function accounts for the fact that '/a/b/c' and 'a/b/c/' are
    children of '/a/b' (and also of '/a/b/').
    Note that '/a/b/cd' is NOT a child of 'a/b/c'.
    r  )rá   r'  ri   ©r§  r¨  s     r*   Úis_child_urir«  )  sM   € ô 	ˆZÓò 	KÜ�‹Oò	Kà×Ñ˜SÓ!×,Ñ,¨Z×->Ñ->¸sÓ-CÀcÑ-IÓJðr)   c                 ó|   — | xr9 |xr5 |j                  d«      dz   j                  | j                  d«      dz   «      S )zëReturn True, if child_uri is a child of parent_uri or maps to the same resource.

    Similar to <util.is_child_uri>_ ,  but this method also returns True, if parent
    equals child. ('/a/b' is considered identical with '/a/b/').
    r  )r'  ri   rª  s     r*   Úis_equal_or_child_urir­  7  sI   € ð 	ò 	SØò	Sà×Ñ˜cÓ" SÑ(×4Ñ4°Z×5FÑ5FÀsÓ5KÈcÑ5QÓRðr)   c                 óz  — | d   dz   }| j                  d«      r	|| d   z  }n7|| d   z  }| d   dk(  r| d   dk7  r|d| d   z   z  }n| d   d	k7  r|d| d   z   z  }|t        | j                  d
d«      «      z  }|€<|t        | j                  dd«      «      z  }| j                  d«      r|d| d   z   z  }|S ||z  }|S )zsURL reconstruction according to PEP 333.
    @see https://www.python.org/dev/peps/pep-3333/#url-reconstruction
    zwsgi.url_schemez://Ú	HTTP_HOSTÚSERVER_NAMEÚhttpsÚSERVER_PORTÚ443ú:Ú80ÚSCRIPT_NAMEr#   Ú	PATH_INFOÚQUERY_STRINGú?)r»   r   )ri  Ú	local_uriÚurls      r*   Úmake_complete_urlr¼  D  s   € ð Ð#Ñ
$ uÑ
,€Cà‡{�{�;ÔØˆw�{Ñ#Ñ#‰àˆw�}Ñ%Ñ%ˆàÐ$Ñ%¨Ò0Ø�}Ñ%¨Ò.Ø�s˜W ]Ñ3Ñ3Ñ3‘à�}Ñ%¨Ò-Ø�s˜W ]Ñ3Ñ3Ñ3�àŒ5�—‘˜]¨BÓ/Ó0Ñ0€CàÐØŒu�W—[‘[ ¨bÓ1Ó2Ñ2ˆØ�;‰;�~Ô&Ø�3˜ Ñ0Ñ0Ñ0ˆCð €Jð 	ˆyÑˆØ€Jr)   c                 ó"  — |D ��ci c]  \  }}|j                  «       ||f“Œ }}}t        | «      D ]0  \  }\  }}|j                  |j                  «       d«      }|€Œ,|| |<   Œ2 |j                  «       D ]  }	| j	                  |	«       Œ yc c}}w )z@Modify or append new headers to existing header list (in-place).N)rö   Ú	enumeraterh   rv   r�   )
ÚtargetÚ	new_itemsrå   rw   Únew_dictÚidxrí   Ú_valueÚnew_valrq   s
             r*   Úupdate_headers_in_placerÅ  a  s˜   € à.7×8¡d a¨�—‘“	˜A˜q˜6Ñ!Ð8€HÑ8Ü(¨Ó0ò "Ñˆ‰^ˆd�FØ—,‘,˜tŸz™z›|¨TÓ2ˆØÑØ!ˆF�3ŠKð"ð —‘Ó"ò ˆØ�‰�eÕðð ùó 9s   †B)Úallow_emptyc                óÄ  — | j                  dd«      j                  «       }|dk(  rd}nC	 t        |«      }|dk  rt        t        d«      ‚	 |dk(  rd}n| d   j                  |«      }d| d	<   |dk(  r|ryt        t        d
«      ‚	 t        r,t        j                  |t        j                  d¬«      ¬«      }nt        j                  |«      }| j                  d«      rAt        j                  dj                  | d   t!        t#        |d¬«      «      «      «       d| d<   |S # t
        $ r t        t        d«      d‚w xY w# t        $ r}t        t        d|¬«      d‚d}~ww xY w)añ  Read request body XML into an etree.Element.

    Return None, if no request body was sent.
    Raise HTTP_BAD_REQUEST, if something else went wrong.

    TODO: this is a very relaxed interpretation: should we raise HTTP_BAD_REQUEST
    instead, if CONTENT_LENGTH is missing, invalid, or 0?

    RFC: For compatibility with HTTP/1.0 applications, HTTP/1.1 requests containing
    a message-body MUST include a valid Content-Length header field unless the
    server is known to be HTTP/1.1 compliant.
    If a request contains a message-body and a Content-Length is not given, the
    server SHOULD respond with 400 (bad request) if it cannot determine the
    length of the message, or with 411 (length required) if it wishes to insist
    on receiving a valid Content-Length."

    So I'd say, we should accept a missing CONTENT_LENGTH, and try to read the
    content anyway.
    But WSGI doesn't guarantee to support input.read() without length(?).
    At least it locked, when I tried it with a request that had a missing
    content-type and no body.

    Current approach: if CONTENT_LENGTH is

    - valid and >0:
      read body (exactly <CONTENT_LENGTH> bytes) and parse the result.
    - 0:
      Assume empty body and return None or raise exception.
    - invalid (negative or not a number:
      raise HTTP_BAD_REQUEST
    - missing:
      NOT: Try to read body until end and parse the result.
      BUT: assume '0'
    - empty string:
      WSGI allows it to be empty or absent: treated like 'missing'.
    rg  r#   r   zNegative content-length.zcontent-length is not numeric.Nrm  ra   rl  zBody must not be empty.F)Úresolve_entities)ÚparserzInvalid XML format.)r‚  zwsgidav.dump_request_bodyz{} XML request body:
{}ÚREQUEST_METHODT©Úpretty)r»   rS   rk   r   r   rf   rt  r   r   ÚXMLÚ	XMLParserÚ
fromstringr°   rë   Úinfor‚   rK   r   )ri  rÆ  ÚclHeaderÚrequestbodyÚcontent_lengthÚrootELrÔ   s          r*   Úparse_xml_bodyrÕ  s  s|  € ðL �{‰{Ð+¨RÓ0×6Ñ6Ó8€Hà�2‚~ð ‰ð	YÜ  ›]ˆNØ Ò!ÜÔ/Ð1KÓLÐLð "ð
 ˜QÒØ‰Kà! ,Ñ/×4Ñ4°^ÓDˆKØ01ˆGÐ,Ñ-à�bÒÙØäÔ+Ð-FÓGÐGð
ÝÜ—Y‘YØ¤E§O¡OÀUÔ$Kô‰Fô ×%Ñ% kÓ2ˆFð ‡{�{Ð.Ô/Ü�‰Ø&×-Ñ-ØÐ(Ñ)Ü”| F°4Ô8Ó9óô	
ð 05ˆÐ+Ñ,à€MøôK ò 	YÜÔ+Ð-MÓNÐTXÐXð	Yûô, ò ÜÜÐ3À1ô
àð	ûðús$   ª D  ÂAD> Ä D;Ä>	EÅEÅEc          	      óJ   —  |dddt        «       fdt        |«      fg«       dgS )ú4Start a WSGI response for a DAVError or status code.z301 Moved Permanently©úContent-LengthÚ0ÚDateÚLocationr)   )rž   r   )ri  Ústart_responseÚlocations      r*   Úsend_redirect_responserß  Ú  s8   € ñ Øà#ØÔ%Ó'Ð(Øœ˜x›Ð)ð	
ôð ˆ5€Lr)   )r„  Úis_headc                ó  — t        |«      }g }|r|j                  |«       t        |t        «      r'|j                  r|j                  |j                  «       |t
        t        fv r ||ddt        «       fg|z   «       dgS |t        t        fv rt        |«      }t        |t        «      sJ |«       ‚|j                  «       \  }}|rd}t        |«      sJ |«       ‚ ||d|fdt        «       fdt        t        |«      «      fg|z   «       |gS )r×  rØ  rÛ  r)   úContent-TyperÙ  )r   Úextendr=   r   r„  r   r   rž   r   r   Úget_response_pagerB   r4   r  )	ri  rÝ  rÔ   r„  rà  r–  ÚheadersÚcontent_typer|  s	            r*   Úsend_status_responserç  è  s  € ô $ AÓ&€FØ€GÙØ�‰�{Ô#Ü�!”XÔ 1§=¢=Ø�‰�q—}‘}Ô%ð 	Ô¤Ð0Ñ0áØÐ,¨vÔ7GÓ7IÐ.JÐKÈgÑUô	
ð ˆuˆàŒW”lÐ#Ñ#Ü�Q‹KˆÜ�aœÔ"Ð% AÓ%Ð"à×,Ñ,Ó.Ñ€L�$ÙØˆä�DŒ>Ð˜4Óˆ>ÙØà˜\Ð*ØÔ%Ó'Ð(Øœs¤3 t£9›~Ð.ð	
ð
 ñ	ôð ˆ6€Mr)   c           	      ó  — | j                  d«      r.dj                  | d   t        t        |d¬«      «      «      }|| d<   t        |d¬«      }t	        |«      sJ |«       ‚ddt        «       fd	t        t        |«      «      fg} |d
|«       |gS )Nzwsgidav.dump_response_bodyz{} XML response body:
{}rÊ  TrË  F)râ  zapplication/xml; charset=utf-8rÛ  rÙ  z207 Multi-Status)r»   r‚   rK   r   rB   rž   r4   r  )ri  rÝ  Úmultistatus_elemÚxmlÚxml_datarå  s         r*   Úsend_multi_status_responserì    s§   € ð ‡{�{Ð/Ô0Ø)×0Ñ0ØÐ$Ñ%Ü”<Ð 0¸Ô>Ó?ó
ˆð 14ˆÐ,Ñ-ô
 Ð,°UÔ;€Hä�HÔÐ'˜xÓ'Ðð 	;Ø	Ô!Ó#Ð$Ø	œ3œs 8›}Ó-Ð.ð€Gñ Ð% wÔ/Øˆ:Ðr)   c                 óÊ  — d}i }i }i }|D ]u  \  }}d}	t        |t        «      rt        |«      }	d}t        |«      \  }
}|
dk7  r|
|vr|
dk7  rd||
<   |
|d|› �<   |dz  }|j	                  |	g «      j                  ||f«       Œw t        | d|¬	«      }|t        j                  |d
«      _	        |D ]³  }	t        j                  |d«      }t        j                  |d«      }||	   D ]_  \  }}|€t        j                  ||«       Œt        |«      r|j                  |«       Œ<t        |«      t        j                  ||«      _	        Œa d|	› �t        j                  |d«      _	        Œµ y)aî  Append <response> element to <multistatus> element.

    <prop> node depends on the value type:
      - str or unicode: add element with this content
      - None: add an empty element
      - etree.Element: add XML element as child
      - DAVError: add an empty element to an own <propstatus> for this status code

    @param multistatus_elem: etree.Element
    @param href: global URL of the resource, e.g. 'http://server:port/path'.
    @param prop_list: list of 2-tuples (name, value)
    ra   z200 OKNzDAV:r#   TÚNSz{DAV:}response)Únsmapz
{DAV:}hrefz{DAV:}propstatz
{DAV:}propz	HTTP/1.1 z{DAV:}status)r=   r   r   r2  Ú
setdefaultr�   r   r   Ú
SubElementÚtextr   r5  )ré  ÚhrefÚ	prop_listÚnsCountÚnsDictÚnsMapÚpropDictrí   rq   r–  r0  Ú_Ú
responseELÚ
propstatELÚpropELs                  r*   Úadd_property_responserý  3  sŽ  € ð €GØ€FØ€EØ€Hà ò >‰ˆˆeØˆÜ�eœXÔ&Ü+¨EÓ2ˆFàˆEô   Ó%‰ˆˆAØ�Š<˜B fÑ,°°r²ØˆF�2‰JØ$&ˆE�B�w�i�.Ñ!Ø�q‰LˆGà×Ñ˜F BÓ'×.Ñ.°°e¨}Õ=ð>ô$ "Ð"2Ð4DÈEÔR€Jð 7;„E×Ñ�Z Ó.Ô3ð
 ò QˆÜ×%Ñ% jÐ2BÓCˆ
ä×!Ñ! *¨lÓ;ˆØ# FÑ+ò 		M‰KˆD�%Øˆ}Ü× Ñ  ¨Õ.Ü! %Ô(Ø—‘˜eÕ$ô
 7FÀeÓ6L”× Ñ  ¨Ó.Õ3ð		Mð ?HÈÀxÐ<PŒ×Ñ˜ ^Ó4Õ9ñQr)   c                 óJ   — t        | «      } t        | «      j                  «       S )zReturn md5 digest for a string.)rI   r   Ú	hexdigestr?   s    r*   Úcalc_hexdigestr   x  s   € ä�‹€AÜˆq‹6×ÑÓÐr)   c                 ót   — t        | «      } t        j                  | «      j                  «       } t	        | «      S )z#Return base64 encoded binarystring.)rI   Úbase64ÚencodebytesrS   rK   r?   s    r*   Úcalc_base64r  ~  s.   € ä�‹€AÜ×Ñ˜1Ó×#Ñ#Ó%€AÜ�!‹9Ðr)   )rX  c                ó|   — | €|ry| j                  «       } | rd| v s| j                  d«      rt        d| ›d�«      ‚| S )a?  Validate etag string to ensure propare comparison.

    This function is used to assert that `DAVResource.get_etag()` does not add
    quotes, so it can be passed as `ETag: "<etag_value>"` header.
    Note that we also reject weak entity tags (W/"<etag_value>"), since WebDAV
    servers commonly use strong ETags.
    Nú"úW/úInvalid ETag format: 'ú'.)rS   ri   rf   )ÚetagrX  s     r*   Úchecked_etagr  …  sG   € ð €|™
ØØ�:‰:‹<€DÙ�3˜$‘; $§/¡/°$Ô"7äÐ1°$°¸Ð<Ó=Ð=Ø€Kr)   c                 ó  — g }| j                  d«      D ]o  }t        |j                  «       d«      }|j                  d«      r|j	                  d«      r|dd }|r|j                  |«       ŒXd|v sŒ]t        t        d| ›d�«      ‚ |S )au  Return a list of etag-values for a `If-Match` or `If-Not-Match` header.

    Remove enclosing quotes for easy comparison with the `DAVResource.get_etag()`
    results.
    We strip the weak-ETag prefix, because WebDAV servers commonly use strong
    ETags. If the client sends a weak tag, it should not hurt to compare
    against the resources strong etag however(?).
    rO   r  r  ra   rb   r  r	  )rT   r  rS   ri   rj   r�   r   r   )rq   rZ   r
  s      r*   Úparse_if_match_headerr  –  sŒ   € ð €CØ—‘˜CÓ ò SˆÜ˜DŸJ™J›L¨$Ó/ˆØ�?‰?˜3Ô D§M¡M°#Ô$6Ø˜˜"�:ˆDÙØ�J‰J�tÕØ�DŠ[äÔ+Ð/EÀeÀYÈbÐ-QÓRÐRðSð €Jr)   c                 ó   — t        | «      rt        | «      }n| }| j                  dd«      } t        j                  j                  |«      st        | «      j                  «       S t        j                  |«      }t        j                  dk(  rEt        | «      j                  «       › d|t        j                     › d|t        j                     › �}|S |t        j                     › d|t        j                     › d|t        j                     › �}|S )a%  Return a strong, unquoted Entity Tag for a (file)path.

    http://www.webdav.org/specs/rfc4918.html#etag

    Returns the following as entity tags::

        Non-file - md5(pathname)
        Win32 - md5(pathname)-lastmodifiedtime-filesize
        Others - inode-lastmodifiedtime-filesize
    r4  r‹   Úwin32ú-)rB   r5  r�   rB  r  Úisfiler   rÿ  Ústatr1   ÚplatformÚST_MTIMEÚST_SIZEÚST_INO)Ú	file_pathÚunicode_file_pathÚfstatr
  s       r*   Úget_file_etagr  ¬  sì   € ô �	ÔÜ+¨IÓ6Ñà%ÐØ×$Ñ$ VÐ->Ó?ˆ	ä�7‰7�>‰>Ð+Ô,Ü�9‹~×'Ñ'Ó)Ð)ä�G‰GÐ%Ó&€EÜ
‡|�|�wÒä�9‹~×'Ñ'Ó)Ð*¨!¨E´$·-±-Ñ,@Ð+AÀÀ5ÌÏÉÑCVÐBWÐXð 	ð
 €Kð œŸ™Ñ$Ð% Q u¬T¯]©]Ñ';Ð&<¸A¸eÄDÇLÁLÑ>QÐ=RÐSˆØ€Kr)   z(([0-9]+)-([0-9]*))z(-([0-9]+))c           	      óÜ  — g }| j                  d«      }|D �]  }d}|s²t        j                  |«      }|r›t        |j	                  d«      «      }||k\  rt        t        d|› d|› d�dd|› �fg¬	«       |j	                  d
«      dk(  r|dz
  }nt        |j	                  d
«      «      }||k  r$||k  r||k\  r|dz
  }|j                  ||f«       d}|rŒ½t        j                  |«      }|sŒÕ|t        |j	                  d«      «      z
  }|dk  rd}|dz
  }|j                  ||f«       d}�Œ |j                  «        g }	d}
t        |«      dkD  rœ|j                  «       \  }}t        |«      }|dkD  rE||dz
     \  }}||dz
  k  s||dz   kD  rnt        ||«      }t        ||«      }||dz
  = |dz
  }|dkD  rŒE|	j                  ||||z
  dz   f«       |
|z   |z
  dz   }
t        |«      dkD  rŒœ|	|
fS )ap  
    See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range

    Return tuple (range_list, total_length)

    range_list
        content ranges as values to their parsed components in the tuple
        (seek_position/abs position of first byte, abs position of last byte, num_of_bytes_to_read)
    total_length
        total length for Content-Length
    rO   Fr/   z)Requested range starts behind file size (z >= r.   zContent-Rangezbytes */)r„  r    r#   ra   Tr   )rT   ÚreByteRangeSpecifierÚsearchrk   Úgroupr‰  r   r�   ÚreSuffixByteRangeSpecifierÚsortr  rh   Úminrh  )Úrange_headerÚfilesizeÚlist_rangesÚrequest_rangesÚsubrangeÚ
is_matchedÚmatchÚrange_startÚ	range_endÚlist_ranges_2Útotal_lengthÚ	rfirstposÚrlastposÚcounterÚ	nfirstposÚnlastposs                   r*   Úobtain_content_rangesr2  Ö  sN  € ð €KØ!×'Ñ'¨Ó,€NØ"ó $"ˆØˆ
ÙÜ(×/Ñ/°Ó9ˆEÙÜ! %§+¡+¨a£.Ó1�à (Ò*äÜ2ØCÀKÀ=ÐPTÐU]ÐT^Ð^_Ð`Ø&5¸À(ÀÐ7LÐ%MÐ$Nõð —;‘;˜q“> RÒ'à (¨1¡‘Iô !$ E§K¡K°£NÓ 3�Ià )Ò+°¸hÒ0FØ  HÒ,Ø$,¨q¡L˜	Ø×&Ñ&¨°YÐ'?Ô@Ø!%�JâÜ.×5Ñ5°hÓ?ˆEÚØ&¬¨U¯[©[¸«^Ó)<Ñ<�Ø ’?Ø"#�KØ$ q™L�	Ø×"Ñ" K°Ð#;Ô<Ø!’
ðI$"ðN ×ÑÔØ€MØ€LÜ
ˆkÓ
˜QÒ
Ø +§¡Ó 1Ñˆ�HÜ�kÓ"ˆØ˜ŠkØ$/°¸!±Ñ$<Ñ!ˆY˜Ø˜) a™-Ò'¨9°xÀ!±|Ò+CØä 	¨9Ó5�	Ü˜x¨Ó2�Ø ¨!¡Ð,Ø ‘kˆGð ˜‹kð 	×Ñ˜i¨°8¸iÑ3GÈ!Ñ3KÐLÔMØ# hÑ.°Ñ:¸QÑ>ˆô ˆkÓ
˜QÓ
ð ˜<Ð(Ð(r)   i Ìzsecond\-([0-9]+)c                 óþ   — d}| j                  d«      }|D ]e  }|j                  «       }|j                  «       dk(  r yt        j	                  |«      }|D ]$  }t        |«      }|t        kD  r  y|dk7  sŒ |c c S  Œg y)z-Return -1 if infinite, else return numofsecs.r   rO   Úinfiniterb   N)rT   rS   rö   ÚreSecondsReaderÚfindallrk   ÚMAX_FINITE_TIMEOUT_LIMIT)ÚtimeoutvalueÚtimeoutsecsÚtimeoutvaluelistÚtimeoutspecÚlistSRr�   s         r*   Úread_timeout_value_headerr=  )  s�   € à€KØ#×)Ñ)¨#Ó.ÐØ'ò 'ˆØ!×'Ñ'Ó)ˆØ×ÑÓ *Ò,Ùä$×,Ñ,¨[Ó9ˆFØò '�Ü! $›i�ØÔ!9Ò9ÚØ !Ó#Ø&Ô&ñ'ð'ð r)   c                 óT  — | syd|v rG| j                  «       r7t        |d   «      }d}|D ]  }||k(  s|dk(  sŒd} n |st        t        d«      ‚d}d|v r'| j	                  «       rt        |d   «      }|r||kD  rd}d}	d|v rZ| j                  «       rJt        |d   «      }|D ]5  }||k(  s|dk(  sŒ|d	   d
v r|st        t        d«      ‚t        t        d«      ‚ d}	d|v r5| j	                  «       r%t        |d   «      }
|
r|
|k  rt        t        d«      ‚|r|	st        t        d«      ‚y)ae  Handle 'If-...:' headers (but not 'If:' header).

    If-Match
        @see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.24
        Only perform the action if the client supplied entity matches the
        same entity on the server. This is mainly for methods like
        PUT to only update a resource if it has not been modified since the
        user last updated it.
        If-Match: "737060cd8c284d8af7ad3082f209582d"
    If-Modified-Since
        @see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25
        Allows a 304 Not Modified to be returned if content is unchanged
        If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
    If-None-Match
        @see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26
        Allows a 304 Not Modified to be returned if content is unchanged,
        see HTTP ETag
        If-None-Match: "737060cd8c284d8af7ad3082f209582d"
    If-Unmodified-Since
        @see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.28
        Only send the response if the entity has not been modified since a
        specific time.
    NÚHTTP_IF_MATCHFÚ*Tz If-Match header condition failedÚHTTP_IF_MODIFIED_SINCEÚHTTP_IF_NONE_MATCHrÊ  )ÚGETÚHEADzIf-None-Match header failedz%If-None-Match header condition failedÚHTTP_IF_UNMODIFIED_SINCEz+If-Unmodified-Since header condition failedz)If-Modified-Since header condition failed)Úsupport_etagr  r   r   Úsupport_modifiedr­   r   )Údav_resÚlast_modifiedÚ
entity_tagri  Ú
token_listr(  ÚtokenÚifModifiedSinceFailedÚ	ifmodtimeÚignoreIfModifiedSinceÚifunmodtimes              r*   Úevaluate_http_conditionalsrQ  A  s†  € ñ0 Øð ˜'Ñ! g×&:Ñ&:Ô&<Ü*¨7°?Ñ+CÓDˆ
ØˆØò 	ˆEØ˜
Ò" e¨s£lØ�Ùð	ñ ÜÔ3Ð5WÓXÐXð "ÐØ 7Ñ*¨w×/GÑ/GÔ/IÜ% gÐ.FÑ&GÓHˆ	Ù˜ ]Ò2Ø$(Ð!ð "ÐØ˜wÑ&¨7×+?Ñ+?Ô+AÜ*¨7Ð3GÑ+HÓIˆ
Øò 	ˆEØ˜
Ò" e¨s£lð Ð,Ñ-°Ñ@Ù1ä"Ô#4Ð6SÓTÐTÜÜ,Ð.Uóð ð	ð !%Ðà! WÑ,°×1IÑ1IÔ1KÜ'¨Ð0JÑ(KÓLˆÙ˜;¨Ò6ÜÜ(Ð*Wóð ñ Ñ%:ÜÔ(Ð*UÓVÐVà
r)   z(\<([^>]+)\>)|(\(([^\)]+)\))z\<([^>]+)\>([^<]+)z\(([^)]+)\)z(\S+)c           	      óü  — d| v ryd| vrd| d<   g | d<   y| d   j                  «       }|j                  d«      sd|z   }t        g «      }g }d}t        j	                  |«      D ]í  \  }}}}|dk7  r|}Œg }	d	}
t
        j	                  |«      D ]   }|j                  «       d
k7  rx|j                  d«      r$|	j                  |
d|j                  d«      f«       nC|	j                  |
d|j                  d«      f«       |j                  |j                  d«      «       |j                  «       d
k7  }
Œ¢ ||v r||   }ng }|||<   |j                  |	«       Œï || d<   || d<   t        j                  dt        |«      › �«       y)z‰Parse HTTP_IF header into a dictionary and lists, and cache the result.

    @see http://www.webdav.org/specs/rfc4918.html#HEADER_If
    zwsgidav.conditions.ifNÚHTTP_IFzwsgidav.ifLockTokenListú<z<*>r@  r#   TÚNOTr_   Úentityz"[]Ú	locktokenz<>zparse_if_header_dict
)rS   ri   rU   ÚreIfSeparatorr6  ÚreIfTagListContentsÚupperr�   rë   rü   r   )ri  ÚiftextÚifDictÚ
ifLockListÚ	resource1Ú	tmpURLVarÚURLVarÚ_tmpContentVarÚ
contentVarÚlistTagContentsÚtestflagÚlistitemÚlistTags                r*   Úparse_if_header_dictrg  �  s¸  € ð
  'Ñ)Øà˜ÑØ+/ˆÐ'Ñ(Ø-/ˆÐ)Ñ*Øà�YÑ×%Ñ%Ó'€FØ×Ñ˜SÔ!Ø˜‘ˆä�"‹X€FØ€Jà€IÜ9F×9NÑ9NÈvÓ9Vò  ,Ñ5ˆ	�6˜>¨:Ø˜Š?Ø‰Ià ˆOØˆHÜ/×7Ñ7¸
ÓCò 5�Ø—>‘>Ó# uÒ,Ø×*Ñ*¨3Ô/Ø'×.Ñ.à (Ø (Ø (§¡¨uÓ 5ðõð (×.Ñ.à (Ø +Ø (§¡¨tÓ 4ðôð #×)Ñ)¨(¯.©.¸Ó*>Ô?Ø#Ÿ>™>Ó+¨uÑ4‘ð'5ð* ˜FÑ"Ø  Ñ+‘à�Ø$+��yÑ!Ø�N‰N˜?Õ+ðA ,ðD (.€GÐ#Ñ$Ø)3€GÐ%Ñ&Ü‡M�MÐ*¬7°6«?Ð*;Ð<Ô=Ø
r)   c           	      ó>  — t         j                  d|› d|› d|› d�«       ||v r||   }nd|v r|d   }ny| j                  «       }|D ]?  }d}|D ]2  \  }	}
}|
dk(  r|r||k(  }n|
dk(  r|	}n|
dk(  r||v }nd}||	k(  }|rŒ0d} n |rŒ? y t         j                  d	«       y)
Nztest_if_header_dict(rP   r.   r@  TFrV  rW  z  -> FAILED)rë   rü   rF  )rH  Úif_dictÚfullurlÚlocktoken_listrJ  ÚlistTestÚsupportEntityTagÚlistTestCondsÚmatchfailedrd  Ú
checkstyleÚ
checkvalueÚ
testresultÚcheckresults                 r*   Útest_if_header_dictrt  Ú  sí   € Ü‡M�MÐ(¨¨	°°NÐ3CÀ2ÀjÀ\ÐQRÐSÔTà�'ÑØ˜7Ñ#‰Ø	�‰Ø˜3‘<‰àð ×+Ñ+Ó-ÐØ!ò ˆØˆà0=ò 	Ñ,ˆH�j *Ø˜XÒ%Ñ*:Ø'¨:Ñ5‘
Ø˜xÒ'Ø%‘
Ø˜{Ò*Ø'¨>Ð9‘
à!�
Ø$¨Ñ0ˆKÚØ"�Ùð	ò Ùð#ô$ ‡M�M�-Ô Ør)   z	audio/oggz	video/oggz
video/webmzapplication/yaml)z.ogaz.oggz.ogvz.webmz.ymlz.yamlr»  rþ   c                 óF  — t        j                  | «      \  }}|r|j                  d«      nd}|sRt        j                  j                  | «      d   }t        j                  |«      }t        j                  d| › d|› �«       |sd}|j                  d«      r
|r|d|› �z  }|S )	z‚Use the mimetypes module to lookup the type for an extension.

    This function also adds some extensions required for HTML5
    Údefault_charsetNra   z	mimetype(z): zapplication/octet-streamztext/z
; charset=)
Ú	mimetypesÚ
guess_typer»   rB  r  rC  Ú_MIME_TYPESrë   rü   ri   )r»  rþ   ÚmimetypeÚ_mimeencodingrv  rD  s         r*   Úguess_mime_typer|    sž   € ô
 !*× 4Ñ 4°SÓ 9Ñ€Xˆ}Ù8?�g—k‘kÐ"3Ô4ÀT€OÙÜ�g‰g×Ñ˜sÓ# AÑ&ˆÜ—?‘? 3Ó'ˆÜ�‰˜	 #  c¨(¨Ð4Ô5ÙØ-ˆØ×Ñ˜7Ô#©Ø�j Ð 1Ð2Ñ2ˆØ€Or)   )r4  rÜ   )F)r,   N)‹r'   r  r©   Úcollections.abcrÞ   rµ   rw  rB  r  Úrer  r1   r¡   r5   rã   r   Úemail.utilsr   r   Úhashlibr   Úpprintr   Útypingr   r	   r
   r   Úurllib.parser   r   r   Úwsgidav.dav_errorr   r   r   r   r   r   r   r   r   r   Úwsgidav.xml_toolsr   r   r   r   r   Ú__docformat__rÁ   rÀ   rë   r3   r2   r4   r7   ÚgetfilesystemencodingrŽ   Úpublic_wsgidav_infoÚpublic_python_infor"   rá   r;   r@   rB   rD   rI   rK   rQ   r[   rc   rz   r‰   r‘   r“   r—   rž   r¤   r¦   r­   r¨   rÖ   rÚ   rä   rò   r  r  r  r  r  r!  r$  r+  r2  r5  r<  r@  rE  rU  re  rj  r€  r‰  r‹  r&  r¤  r¦  r«  r­  r¼  rÅ  rÕ  rß  rç  rì  rý  r   r  r  r  r  Úcompiler  r  r2  r7  ÚIr5  r=  rQ  rX  Ú
reIfHeaderÚreIfTagListrY  rg  rt  ry  r|  r?   s   0r*   ú<module>rŽ     s	  ðñ
ó Û Û Û Û Û 	Û Û 	Û Û 
Û Û Ý ß -Ý Ý ß 2Ó 2Ý å ÷÷ ÷ ÷õ ð #€ð Ð Ø
ˆ'×
Ñ
Ð,Ó
-€ð —‘¨3×+;Ñ+;¸B¸QÐ+?Ö@ a™3˜q�6Ò@ÓA€à.�S×.Ñ.Ó0Ð ð
 !  Ð.Ð ð ˜~Ð.Ð/Ð ÷ñ ð e¨C¡jð °Tó ò&'ò
 ò
ó
óð !¨eò ¸ó ð )3ð :¸uô :ð@ $)ô ð, $(°TÀEô 2òpPò"ð (/¸ò �cð À3ó ó2BóBóAò
ò"òFyðx 9>ô òò.ð  >BÈtô GðT <@ô IñN�Cð  ð °4ð ÀCó òòòò,'òSòòð .@ô ò&	òð "¨U¸TÐPTô$,ðN )-¸È$ô  òLò(GFðX ðð ØØØô÷8#ñ #ò>'ð)�cð )˜có )ð
3˜ð 3 ¨¡ó 3ð˜Sð ¨Sð °Tó ò
óó:
ð$ ,1ô YòNð 04¸Uô(òVò@=QòJòð &+ô ò"ò,ðL "�r—z‘zÐ"7Ó8Ð Ø'˜RŸZ™Z¨Ó6Ð òG)ð^ 3Ð Ø�"—*‘*Ð0°"·$±$Ó7€òò0Sðl �—
‘
Ð:Ó;€ØˆR�Z‰ZÐ-Ó.€
Øˆb�j‰j˜Ó(€Ø �b—j‘j Ó*Ð ò:òzðR ØØØàØñ€ñ˜ð  x°¡~ð Àô ùòk6 As   Â=K