
    qi              	          S r SSKrSSKrSSKrSSKrSSKrSSKrSSKrSSK	r	SSK
r
SSKrSSKrSSKJr  SSKJrJr  SSKJr  SSKJr  SSKJrJrJr  SSKJr  SS	KJr  SS
KJrJ r J!r!J"r"J#r#J$r$J%r%J&r&J'r'J(r(  SSK)J*r*J+r+J,r,J-r-  Sr.Sr/\R`                  " \/5      r1SRe                  \
Rf                  SS  V s/ s H  n \4" U 5      PM     sn 5      r5\
Rl                  " 5       r7S\ 3r8S\5 3r9 " S S5      r:S\\4   S\;4S jr<S r=S r>S r?S|S jr@S|S jrASSS.S\B4S jjrC\:4SS.S  jjrDSS!.S" jrESS#SS$.S% jrFS& rGS' rHS(SS).S*\4S\44S+ jjrIS}S, jrJS}S- jrKS}S. jrLS/ rMS0 rNS1 rOSS2.S3 jrPS4 rQS5 rRSS#S6.S7 jrSSS8.S9 jrTS~S*\4S:\4S;\;S\44S< jjrUS= rVS> rWS? rXS@ rYSA rZSB r[SCSD.SE jr\SF r]SG r^S#SS#S#SH.SI jr_S#S#S#SJ.SK jr`SL raSM rb S}SSSSN.SO jjrc " SP SQ5      rdSR reSS\4S\44ST jrfSS\4S\\4   4SU jrgSV\4SW\4S\;4SX jrhSY riS}SZ jrjSS[ jrkSS\.S] jrlS^ rmSSS_.S` jrnSa roSb rpSc rqSd rrSSe.Sf jrsSg rtSh ru\R                  " Si5      rw\R                  " Sj5      rxSk rySlrz\R                  " Sm\R                  5      r|Sn r}So r~\R                  " Sp5      r\R                  " Sq5      r\R                  " Sr5      r\R                  " Ss5      rSt rSu rSvSvSwSxSySySz.rS{ rgs  sn f )z.
Miscellaneous support functions for WsgiDAV.
    N)deepcopy)
formatdate	parsedate)md5)pformat)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xml_to_bytesreStructuredTextwsgidav.   zWsgiDAV/zPython/c                       \ rS rSrSrSrg)
NO_DEFAULT=     N)__name__
__module____qualname____firstlineno____doc____static_attributes__r#       A/home/kali/flask_env/lib/python3.13/site-packages/wsgidav/util.pyr    r    =   s    
r*   r    min_versionreturnc                     [         R                  U :  aT  SR                  U SS  Vs/ s H  n[        U5      PM     sn5      n[        R
                  " SU S[         S3[        SS9  g	g
s  snf )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<   A   so    
+%((KO<OqCFO<=4WI >$%Q(		
  =s   A*c                 .    [        U [        [        45      $ )zNReturn True for any string type (for str/unicode on Py2 and bytes/str on Py3).)
isinstancer5   bytesr:   s    r+   is_basestringrA   T   s    a#u&&r*   c                 "    [        U [        5      $ )z>Return True for bytestrings (for str on Py2 and bytes on Py3).)r>   r?   r@   s    r+   is_bytesrC   Y   s    ar*   c                 "    [        U [        5      $ )z8Return True for native strings (for str on Py2 and Py3).)r>   r5   r@   s    r+   is_strrE   ^   s    ar*   c                 @    [        U 5      [        La  [        X5      n U $ )zLConvert a text string (unicode) to bytestring (str on Py2 and bytes on Py3).)typer?   r:   encodings     r+   to_bytesrJ   c   s    Awe!Hr*   c                 ~    [        U 5      [        L a  [        X5      n U $ [        U 5      [        La  [        U 5      n U $ )zGConvert data to native str type (bytestring on Py2 and unicode on Py3).)rG   r?   r5   rH   s     r+   to_strrL   j   s;    Aw% H 
a	FHr*   F)or_noneraise_errorc                   [        5       n[        U 5      [         L a  U nU$ [        U 5      [        L a4  [        [        [        R                  U R                  S5      5      5      nU$ [        U [        [        [        45      (       a  [        [        [        U 5      5      nU$ U c  U(       a  S nU$ U(       a  [        U  S[        U 5       35      eU$ )N,, )setrG   r5   mapstripsplitr>   dictlisttuple	TypeError)valrM   rN   ress       r+   to_setr\   s   s    
%CCyC J 
cc	#cii301 J 
C$e,	-	-#c3- 
 J	 
 J 
3%r$s)-..Jr*   )as_dictc                   U(       a   [        X0 S9nUb  U$ 0 $ U[
        La   [        X5      $ UR                  S5      nUR                  S5      nX   nU(       a  UR                  S5      n[        U[        5      (       a  Xv   nOr[        U[        [        45      (       aK  UR                  S5      (       a  UR                  S5      (       d  [        S5      eUSS nU[        U5         nO [        Xv5      nU(       a  M  U$ ! [        [        [        [        4 a    0 s $ f = f! [        [        [        [        4 a    Us $ f = f! [         a    e f = f)	a  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    rU   popr>   rV   rW   rX   
startswithendswithintgetattr)dkey_pathr_   r]   r[   seg_listsegvalues           r+   rd   rd      sH   2 	 b9C/31r1 j 	!!.. ~~c"H
,,q/CFE
ll1oeT""JEe}-->>#&&cll3.?.? !KLLa)C#c(OE+ (  L; *jA 	I	 *jA 	N	( " s3   D D 
D& .E D#"D#&EEE)in_placec                   ^ U4S jmU(       d  [        U 5      n U R                  5        H  nT" U5        M     U(       a  g U $ )Nc                    > [        U [        5      (       a+  SU ;   a  SU S'   U R                  5        H  nT" U5        M     g [        U [        5      (       a(  [        U [        5      (       d  U  H  nT" U5        M     g g g )Npasswordz	<REMOVED>)r>   rV   valuesr   r5   )vele_purges     r+   rz   purge_passwords.<locals>._purge   sj    aQ +*xxzs "8$$Z3-?-?s  .@$r*   )r   rw   )rn   rs   rx   rz   s      @r+   purge_passwordsr|      s:     QKXXZq	  Hr*   T)msgrN   requiredc                
   U(       d   S5       e[        U5      nUnUSL a  Un[        5       nO4U(       a-  [        U5      nUR                  U5      nUR                  U5      n[        U 5      n / nU R                  U5      nU(       a/  UR	                  SR                  SR                  U5      5      5        U(       aG  UR                  U 5      nU(       a/  UR	                  SR                  SR                  U5      5      5        U(       a  U(       a  UR                  SU5        U(       aG  U(       a@  UR	                  SR                  SR                  U5      SR                  U5      5      5        OmU(       a0  UR	                  SR                  SR                  U5      5      5        O6U(       a/  UR	                  S	R                  SR                  U5      5      5        S
R                  U5      nU(       a  [        U5      eU$ g)zCheck 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\   rR   union
differenceappendformatr4   insertrg   )	tagsknownr}   rN   r~   optionalr[   unknownmissings	            r+   
check_tagsr      s    %%%55MEH45	(#H%##H-$<D
Cooe$G

?))&++g*>?@%%d+JJ--fkk'.BCD
JJq#JJ4;;KK)6;;x+@
 JJ)00X1FGHJJ)00X1FGHiinS/!
r*   c                 L    U R                  [        S5      R                  S5      $ )zDConvert an environment variable to a WSGI 'bytes-as-unicode' string.surrogateescape
iso-8859-1)encodefilesystemencodingdecode)us    r+   unicode_to_wsgir     s"     88&(9:AA,OOr*   c                 $    U R                  S5      $ )zConvert 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     88L!!r*   zutf-8)rI   fallbackr:   c                     [        U 5      [        L a  U R                  U5      $ U R                  S5      R                  U5      $ ! [         a    U(       a  U s $ e f = f)zConvert 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   )rG   r?   r   r   UnicodeDecodeError)r:   rI   r   s      r+   re_encode_wsgir      sV    7e88H%%xx%,,X66 Hs   "A A AAc                     [        U SSS9$ )zMReturn <secs> in rfc 1123 date/time format (pass secs=None for current date).FT)timeval	localtimeusegmt)r   secss    r+   get_rfc1123_timer   9  s     deDAAr*   c                 X    [         R                  " S[         R                  " U 5      5      $ )zReturn <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   ?  s     ==-t{{4/@AAr*   c                 X    [         R                  " S[         R                  " U 5      5      $ )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   H  s    ==,dkk$.?@@r*   c                 T    [        U 5      nU(       a  [        R                  " U5      $ g)aP  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   M  s#     Z(Fv&&r*   c                 *    [         R                  " U S5      $ ! [         a     Of = f [         R                  " U S5      $ ! [         a     Of = f [         R                  " U S5      $ ! [         a     Of = f [        U 5      $ ! [         a     gf = f)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   ^  s    }}Z)DEE }}Z)CDD }}Z)?@@ 
$$ sA    
&&A 
AAA) )
A65A6:
B 
BBc                    SSK JnJn  U R                  SS5      nU R                  S5      =(       d    0 nUR                  S/ 5      nUc  / nUR                  SU5      nUR                  S	U5      n[        R
                  " Xv5      n[        R                  " [        R                  5      n	U	R                  U5        [        R                  " [        5      n
US
:  a   U
R                  [        R                  5        OUS:X  a   U
R                  [        R                  5        OkUS:X  a   U
R                  [        R                  5        OEUS:X  a   U
R                  [        R                   5        OU
R                  [        R"                  5        SU
l        U
R&                  SS  H5  n UR)                  5         UR+                  5         U
R/                  U5        M7     U
R1                  U	5        US:  au  U Ho  nUR3                  [        S-   5      (       d  [        S-   U-   n[        R                  " UR5                  5       5      nUR                  [        R                  5        Mq     g! [,         a     Nf = f)a8
  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   r0   rb   Fr   )wsgidav.default_confr   r   getr   	FormatterStreamHandlerr2   stdoutsetFormatter	getLoggerBASE_LOGGER_NAMEsetLevelDEBUGINFOWARNERRORCRITICAL	propagatehandlersflushcloser   removeHandler
addHandlerrj   rT   )configr   r   r   log_optsr   r   r   	formatterconsoleHandlerloggerhdlrelgs                 r+   init_loggingr     s   t WjjA&Gzz)$*H\\"2B7N!&:<VWLL2GHM !!-DI **3::6N	* /0F!|&	A%	A%	A& 	(() F "	JJLJJL 	T" # n%!|A<< 03 677$s*Q.""1779-BKK&	  
   		s   & I((
I54I5)default_to_verbosec                    U R                  [        S-   5      (       d  [        S-   U -   n [        R                  " U 5      nU$ )z[Create a module logger, that can be en/disabled by configuration.

@see: unit.init_logging
r   )rj   r   r   r   )
moduleNamer   r   s      r+   get_module_loggerr     sA       !1C!788%+j8
z*F Mr*   c                 h   UR                  5        H  u  p#[        U[        R                  R                  5      (       ak  U R                  U5      nUb#  [        U5      [        [        [        [        4;   a  UR                  5       X'   My  [        U R                  U0 5      U5      X'   M  X0U'   M     U $ N)itemsr>   collectionsabcMappingr   rG   boolfloatrl   r5   copydeep_update)rn   r   krx   prev_vals        r+   r   r     s    	a0011uuQxH4>dE35L#Lvvx #155B<3aD  Hr*   c                     SSK nSU ;  a  [        SU < 35      eU R                  SS5      u  p# UR                  U5      n[        XC5      nU$ ! [         a"  n[
        R                  SU < SU 35        e SnAff = f)zBImport a class from a module string, e.g. ``my.module.ClassName``.r   Nr   z%Expected `path.to.ClassName` string: rb   zDynamic import of z	 failed: )	importlibrg   rsplitimport_moduler   _loggererrorrm   )namer   module_name
class_namemoduler   	the_classs          r+   dynamic_import_classr   "  s    
$@IJJ"kk#q1K((5 +I	  *4()A3?@s   A 
A9A44A9)expandrN   c                  ^ U4S jn[        USS1SU  3S9  UR                  S5      =(       d    / nUb)  [        U[        [        45      (       d  [        SU 35      eUR                  S5      =(       d    0 nUb#  [        U[        5      (       d  [        SU 35      e Sn[        U 5      n[        [        XE5      5      nUR                  5        V	V
s0 s H  u  pX" U
5      _M     nn	n
U" U0 UD6nU Vs/ s H  o PM     snUR                  5        V	V
s/ s H  u  pU	 S	U
< 3PM     sn
n	-   n[        R                  S
R                  U SR                  U5      U5      5        U$ s  sn
n	f s  snf s  sn
n	f ! [         a?    SU  SU S3nU(       a  [        R                  U5        e [        R!                  U5         W$ f = f)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                 h   > T(       a)  [        U 5      (       a  U R                  5       T;   a  TU    $ U $ )z2Replace some string templates with defined values.)rA   lower)rx   r   s    r+   _expand*dynamic_instantiate_class.<locals>._expandI  s,    mA&&1779+>!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 {}({}) => {}rQ   zInstantiate (z) failed)r   r   r>   rX   rW   rg   rV   r   rS   r   r   debugr   r4   r   r   	exception)r   optionsr   rN   r   pos_argsr   instr   r   rx   o	disp_argsr}   s     `           r+   dynamic_instantiate_classr  2  s   . 	6zlC
 {{6"(bHJx%$G$GCG9MNN[["(bF*VT":":EgYOPP(4	W/0,2LLN;NDA!WQZ-N; (-f-%-.XsVX.%+\\^2
%3TQqc1%L^2
 
	 	&--j$))I:NPTU	
 K3 < / 2
  ZL'(;MM##Ks=   4E9 E('E9 6E.E9 E3+;E9 (E9 9AGGr   c                    [        U 5      [        L a  SU 0n OU R                  5       n [        U 1 SkSSS9  U R	                  S5      n[        X US9$ )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  )rG   r5   r   r   ri   r  )r  r   r   s      r+   #dynamic_instantiate_class_from_optsr
  |  sV    & G}G$,,.#1	 W%J$ZHHr*   prefixignore_casec                     U(       a5  U R                  5       R                  UR                  5       5      (       d  U $ OU R                  U5      (       d  U $ U [        U5      S $ )zDReplacement for str.removeprefix() (Py3.9+) with ignore_case option.N)r   rj   len)r:   r  r  s      r+   removeprefixr    sS    wwy##FLLN33H 4 ||F##HS[]r*   c                     U R                  X5      n[        U5      U::  a"  UR                  S5        [        U5      U::  a  M"  U$ )zGSplit string, always returning n-tuple (filled with None if necessary).N)rU   r  r   )r:   sepmaxsplittoks       r+   
save_splitr    s;    
''#
 C
c(h


4 c(h
Jr*   c                     U S;   a  gU R                  S5      (       d   eU R                  S5      R                  S5      u  pnUSU-   4$ )z!Return '/a/b/c' -> ('a', '/b/c').r"   /)r"   r"   r  )rj   lstrip	partition)pathfirst_seprests       r+   pop_pathr    sO    y??3C(2237E3:r*   c                 R    U S;   a  g[        U 5      u  p[        U5      u  p2XSU-   4$ )z$Return '/a/b/c' -> ('a', 'b', '/c').r  )r"   r"   r"   r  )r  )r  r  r  seconds       r+   	pop_path2r!    s2    y4.KED>LF3:&&r*   c                 v    [        U5      u  p#U[        U R                  S5      U5      UR                  S5      4$ )z,Return ('/a', '/b/c') -> ('b', '/a/b', 'c').r  )r  join_urirstrip)script_name	path_infosegmentr  s       r+   
shift_pathr(    s6    Y'MGXk005w?SAQRRr*   c                 x    U R                  S5      (       a!  SU ;   a  U R                  SS5      u  pUSS U4$ SU 4$ )zReturn (namespace, localname) tuple for a property name in Clark Notation.

Namespace defaults to ''.
Example:
'{DAV:}foo'  -> ('DAV:', 'foo')
'bar'  -> ('', 'bar')
{}rb   Nr"   )rj   rU   )
clark_namens	localnames      r+   split_namespacer/    sL     S!!cZ&7"((a012	""
r*   c                      [        U S5      nU$ ! [         a*    [        R                  SU < S35        [        U S5      n U$ f = f)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)rL   rg   r   r   )r:   r   s     r+   to_unicode_safer2    sS    $1f H  $(-RST1l#H$s    0AAbackslashreplaceerrorsc                    U(       d  Sn[        U 5      (       a   U R                  XS9R                  U5      n U $ U R                  XS9R                  U5      n U $ )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)
ASCIIr4  )rC   r   r   )r:   encoding_tor5  s      r+   safe_re_encoder9    sY     {{HH[H077D H HH[H077DHr*   c                     [        U 5      (       a6  U < S3nU  H(  n[        U5      [        L a  [        U5      nUSU-  -  nM*     U$ U  $ )zReturn a string as hex dump.z: z%02x )rC   rG   r5   ord)r:   r[   bs      r+   string_reprr=    sP    {{RjAAw#~F7Q;C  
SMr*   c                 J    [         R                  R                  U 5      S   nU$ )Nrb   )osr  splitext)r  exts     r+   get_file_extensionrB    s     
''

4
 
#CJr*   )thousands_sepr  base1024append_bytesc                   SnSnU(       aA  SnU(       a  U S:  a  US-  nU S-	  n U S:  a  M  OU S:  a  US-  nU S-  n U S:  a  M  / SQU   nU(       a  U S:X  a  S	nOS
nU(       a  U S:  d  U(       a  U S nO[        U 5      nU U U 3$ )z1Convert bytes into human-readable representation.r"   r   i   rb   
   i  g     @@)r"   KMGTPz Bytez Bytesz,d)r5   )	numberrC  r  rD  rE  	magsuffix
bytesuffix	magnitudesnums	            r+   byte_number_stringrR  
  s     IJ	D.Q	2 D. D.Q	&  D. 2)<	Q; J!J&D.I 6{VI;zl++r*   )expand_vars
must_exist
allow_nonec                   U S;   a  U(       a  g[        SU < 35      e[        R                  R                  U 5      (       d  U(       d  [        R                  " 5       nO_[        U5      [        L aM  UR                  S5      nU(       a   [        R                  R                  U5      nO[        R                  " 5       n[        R                  R                  [        R                  R                  X5      5      n U(       a<  [        R                  R                  [        R                  R                  U 5      5      n U(       a3  [        R                  R                  U 5      (       d  [        SU < 35      eU $ )zConvert 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: )rg   r?  r  isabsgetcwdrG   rV   r   dirnameabspathr4   
expandvars
expanduserexists)r  rootrS  rT  rU  config_files         r+   fix_pathrb  1  s     z=12277==99;D$Z4((>2Kww{3yy{wwrww||D78ww!!"''"4"4T":;"''....>$233 Kr*   c           	      n     [        S[        U R                  SS5      5      5      $ ! [         a     gf = f)zDReturn a positive CONTENT_LENGTH in a safe way (return 0 otherwise).r   CONTENT_LENGTH)maxrl   r   rg   )environs    r+   get_content_lengthrg  W  s7    1c'++&6:;<< s   $' 
44c                 
   U R                  S5      (       d  U R                  S5      (       a  g[        U 5      nUS:  d   eUS:X  a  gSnSU S'   U(       a  SU S'   U S   n[        US5      (       a{  [        US	5      (       aj  UR                  S:X  aY  UR                  S:  aH  U(       a  UR                  nOSnUR                  U5      n[        R                  S
U SUSS < S35        ggg[        US5      (       a  [        UR                  S5      (       a~   UR                  nUR                  5       nUR                  S5         U(       a  UnOSnUR                  U5      n[        R                  S
U SUSS < S35        UR                  U5        ggg! [         a%  n[        R                  SW SU 35         SnAN>SnAff = f! [         a.    [        R                  S[        R                  " 5        35         gf = f)aC  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   Trb   
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   rg  hasattrrk  rl  readr   r   rn  
gettimeoutro  OSErrorr   r   r2   exc_info)	rf  clREAD_ALL
wsgi_inputnbodysocktimeoutses	            r+   read_and_discard_inputr}  k  s      {{,--=U1V1V	G	$B7N7	QwH)*G%&,-()&J z;''GJ,I,I
 1$):):Q)>%%??1%DMM1#Z[_`cac[dZggjk *?$ 
W	%	%'*2B2BL*Q*Q	F##Doo'GOOAAAA!q)qc!KDQTRTI=X[\ OOG$+ +R	%"  A?2$?@@A
  	FMM3CLLN3CDE	Fs<   -G
 =F G
 
G"G=G
 GG
 
5HHsrc_exceptionerr_conditionadd_headersc                    [        U [        5      (       a  [        U 5      nO[        U UUUUS9n[        R                  SUR                  5        35        Ue)z$Wrapper to raise (and log) DAVError.r~  zRaising DAVError )r>   r   r   r   r   r   get_user_info)rr   context_infor  r  r  r   s         r+   failr    sW     %##''#
 MM%aoo&7%89:
Gr*   c                   b   ^  \ rS rSrU 4S jr\S 5       r\S 5       r\S 5       rSS jr	Sr
U =r$ )	SubAppStartResponsei  c                 L   > SU l         / U l        S U l        [        TU ]  5         g rW  )_SubAppStartResponse__status&_SubAppStartResponse__response_headers_SubAppStartResponse__exc_infosuper__init__)self	__class__s    r+   r  SubAppStartResponse.__init__  s$    "$r*   c                     U R                   $ r   )r  r  s    r+   statusSubAppStartResponse.status  s    }}r*   c                     U R                   $ r   )r  r  s    r+   response_headers$SubAppStartResponse.response_headers  s    &&&r*   c                     U R                   $ r   )r  r  s    r+   rt  SubAppStartResponse.exc_info  s    r*   c                 (    Xl         X l        X0l        g r   )r  r  r  )r  r  r  rt  s       r+   __call__SubAppStartResponse.__call__  s    "2"r*   )
__exc_info__response_headers__statusr   )r$   r%   r&   r'   r  propertyr  r  rt  r  r)   __classcell__)r  s   @r+   r  r    sN       ' '  # #r*   r  c                 d    SR                  U5      nU(       d  U $ U R                  S5      S-   U-   $ )z=Append segments to URI.

Example: join_uri("/a/b", "c", "d")
r  )r4   r$  )urisegmentssubs      r+   r#  r#    s2    
 ((8
C
::c?S 3&&r*   r  c                 H    U R                  S5      R                  S5      S   $ )z,Return local name, i.e. last segment of URI.r  rc   )rT   rU   r  s    r+   get_uri_namer    s     99S>$R((r*   c                     U (       a  U R                  5       S:X  a  gU R                  S5      R                  SS5      S   S-   $ )zReturn 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  Nrb   r   )rT   r$  r   r  s    r+   get_uri_parentr    s<     #))+$::c?!!#q)!,s22r*   
parent_uri	child_uric                     [        U 5      =(       aD    [        U5      =(       a2    UR                  S5      R                  U R                  S5      S-   5      $ )zReturn 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$  rj   r  r  s     r+   is_child_urir  	  sM     	Z 	KO	KS!,,Z->->s-Cc-IJr*   c                     U =(       a>    U=(       a5    UR                  S5      S-   R                  U R                  S5      S-   5      $ )zReturn 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$  rj   r  s     r+   is_equal_or_child_urir    sI     	 	S	Sc"S(44Z5F5Fs5Kc5QRr*   c                    U S   S-   nU R                  S5      (       a  X S   -  nO9X S   -  nU S   S:X  a  U S   S:w  a  USU S   -   -  nOU S   S	:w  a  USU S   -   -  nU[        U R                  S
S5      5      -  nUcA  U[        U R                  SS5      5      -  nU R                  S5      (       a  USU S   -   -  nU$ X!-  nU$ )zkURL 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   )rf  	local_uriurls      r+   make_complete_urlr  $  s    #
$u
,C{{;{##}%%$%0}%.sW]333}%-sW]3335]B/00CuW[[b122;;~&&3000C J 	Jr*   c                 ,   U VVs0 s H  u  p#UR                  5       X#4_M     nnn[        U 5       H1  u  nu  pgUR                  UR                  5       S5      nUc  M-  XU'   M3     UR                  5        H  n	U R	                  U	5        M     gs  snnf )z@Modify or append new headers to existing header list (in-place).N)r   	enumerateri   rw   r   )
target	new_itemsr   rx   new_dictidxr   _valuenew_valrr   s
             r+   update_headers_in_placer  A  s    .78ida	A6!iH8(0^d,,tzz|T2!3K  1 "e #  9s   B)allow_emptyc                v   U R                  SS5      R                  5       nUS:X  a  SnOE [        U5      nUS:  a  [        [        S5      e US:X  a  SnOU S   R                  U5      nSU S	'   US:X  a  U(       a  g[        [        S
5      e [        R                  " U5      nU R                  S5      (       a>  [        R                  SR                  U S   [        [        USS95      5      5        SU S'   U$ ! [
         a    [        [        S5      Sef = f! [         a  n[        [        SUS9SeSnAff = f)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'.
rd  r"   r   zNegative content-length.zcontent-length is not numeric.Nrj  rb   ri  zBody must not be empty.zInvalid XML format.)r  zwsgidav.dump_request_bodyz{} XML request body:
{}REQUEST_METHODTprettyF)r   rT   rl   r   r   rg   rq  r   
fromstringr   r   infor   rL   r   )rf  r  clHeaderrequestbodycontent_lengthrootELr   s          r+   parse_xml_bodyr  S  s^   L {{+R0668H2~ 	Y ]N!/1KLL "
 QK!,/44^DK01G,-b+-FGG!!+. {{.//&--()|F489	
 05+,MA  	Y+-MNTXX	Y"  31
	s#   !C: D :D
D8#D33D8c                8    U" SSS[        5       4SU4/5        S/$ )4Start a WSGI response for a DAVError or status code.z301 Moved PermanentlyContent-Length0DateLocationr*   )r   )rf  start_responselocations      r+   send_redirect_responser    s4     #%'("	
 5Lr*   )r  is_headc                P   [        U5      n/ nU(       a  UR                  U5        [        U[        5      (       a,  UR                  (       a  UR                  UR                  5        U[
        [        4;   a  U" USS[        5       4/U-   5        S/$ U[        [        4;   a  [        U5      n[        U[        5      (       d   eUR                  5       u  pxU(       a  Sn[        U5      (       d   U5       eU" USU4S[        5       4S[        [        U5      5      4/U-   5        U/$ )r  r  r  r*   Content-Typer  )r   extendr>   r   r  r   r   r   r   r   get_response_pagerC   r5   r  )	rf  r  r   r  r  r  headerscontent_typery  s	            r+   send_status_responser    s    $A&FG{#!X1==q}}% 	00,v7G7I.JKgU	
 uWl##QKa"""",,.LD>>4>\*%'(s3t9~.	

 	 6Mr*   c           
      "   U R                  S5      (       a*  SR                  U S   [        [        USS95      5      nX0S'   [        USS9n[	        U5      (       d   U5       eSS[        5       4S	[        [        U5      5      4/nU" S
U5        U/$ )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   rL   r   rC   r   r5   r  )rf  r  multistatus_elemxmlxml_datar  s         r+   send_multi_status_responser    s     {{/00)00$%< 0>?
 14,-
 ,U;HH'x' 	;	!#$	3s8}-.G %w/:r*   c                    Sn0 n0 n0 nU Hy  u  pxSn	[        U[        5      (       a  [        U5      n	Sn[        U5      u  pU
S:w  a  X;  a  U
S:w  a  SXJ'   XSU 3'   US-  nUR	                  U	/ 5      R                  Xx45        M{     [        U SUS	9nU[        R                  " US
5      l	        U H  n	[        R                  " US5      n[        R                  " US5      nXi    Hg  u  pxUc  [        R                  " X5        M   [        U5      (       a  UR                  U5        MC  [        U5      [        R                  " X5      l	        Mi     SU	 3[        R                  " US5      l	        M     g)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)
rb   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   r/  
setdefaultr   r   r   
SubElementtextr   r2  )r  href	prop_listnsCountnsDictnsMappropDictr   rr   r  r-  _
responseEL
propstatELpropELs                  r+   add_property_responser    sm    GFEH eX&&+E2FE  %<B,rFJ$&Bwi.!qLGFB'..}= !$ ""24DERJ 7;EZ.3
 %%j2BC
!!*l;#+KD}  .!%((e$
 7Fe6L  .3 , ?Hx<P^49 r*   c                 J    [        U 5      n [        U 5      R                  5       $ )zReturn md5 digest for a string.)rJ   r   	hexdigestr@   s    r+   calc_hexdigestr   S  s    Aq6r*   c                 v    [        U 5      n [        R                  " U 5      R                  5       n [	        U 5      $ )z#Return base64 encoded binarystring.)rJ   base64encodebytesrT   rL   r@   s    r+   calc_base64r  Y  s.    A1##%A!9r*   )rU  c                    U c  U(       a  gU R                  5       n U (       a  SU ;   d  U R                  S5      (       a  [        SU < S35      eU $ )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: ''.)rT   rj   rg   )etagrU  s     r+   checked_etagr  `  sJ     |
::<D3$;$//$"7"71$<==Kr*   c                 :   / nU R                  S5       H  n[        UR                  5       S5      nUR                  S5      (       a  UR	                  S5      (       a  USS nU(       a  UR                  U5        Mh  SU;   d  Mp  [        [        SU < S35      e   U$ )a]  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(?).
rP   r  r  rb   rc   r  r	  )rU   r  rT   rj   rk   r   r   r   )rr   r[   r
  s      r+   parse_if_match_headerr  q  s     CC DJJL$/??3DMM#$6$6":DJJtD[+/EeYb-QRR ! Jr*   c                 8   [        U 5      (       a  [        U 5      nOU nU R                  SS5      n [        R                  R                  U5      (       d  [        U 5      R                  5       $ [        R                  " U5      n[        R                  S:X  aE  [        U 5      R                  5        SU[        R                      SU[        R                      3nU$ U[        R                      SU[        R                      SU[        R                      3nU$ )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
r1  r   win32-)rC   r2  r   r?  r  isfiler   r  statr2   platformST_MTIMEST_SIZEST_INO)	file_pathunicode_file_pathfstatr
  s       r+   get_file_etagr    s     	+I6%$$V->?	77>>+,,9~''))GG%&E
||w9~'')*!E$--,@+A5CVBWX 	
 K $%QuT]]';&<AeDLL>Q=RSKr*   z(([0-9]+)-([0-9]*))z(-([0-9]+))c           	         / nU R                  S5      nU GH&  nSnU(       d  [        R                  U5      nU(       a  [        UR	                  S5      5      nXq:  a  [        [        SU SU S3SSU 34/S	9  UR	                  S
5      S:X  a  US-
  nO[        UR	                  S
5      5      nXx::  a#  Xq:  a  X:  a  US-
  nUR                  Xx45        SnU(       a  M  [        R                  U5      nU(       d  M  U[        UR	                  S5      5      -
  nUS:  a  SnUS-
  nUR                  Xx45        SnGM)     UR                  5         / n	Sn
[        U5      S:  a  UR                  5       u  p[        U5      nUS:  aB  X-S-
     u  pXS-
  :  d  XS-   :  a  O[        X5      n[        X5      nX-S-
  	 US-
  nUS:  a  MB  U	R                  XX-
  S-   45        X-   U-
  S-   n
[        U5      S:  a  M  X4$ )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
rP   Fr0   z)Requested range starts behind file size (z >= r/   zContent-Rangezbytes */)r  r   r"   rb   Tr   )rU   reByteRangeSpecifiersearchrl   groupr  r   r   reSuffixByteRangeSpecifiersortr  ri   minre  )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    s)    K!'',N"
(//9E!%++a.1*2CK=PTU]T^^_`&5(7L%M$N ;;q>R' (1I !$EKKN 3I+0F ,$,qL	&&'?@!%Jz.55h?Eu&U[[^)<<?"#K$qL	""K#;<!
I #N ML
k
Q
 + 1k"k$/!$<!Ya-'9!|+C	5	x2!,kG k 	i83G!3KLM#.:Q> k
Q
 ((r*   i zsecond\-([0-9]+)c                    SnU R                  S5      nU Hk  nUR                  5       nUR                  5       S:X  a    g[        R	                  U5      nU H'  n[        U5      nU[        :  a      gUS:w  d  M#  Us  s  $    Mm     g)z-Return -1 if infinite, else return numofsecs.r   rP   infiniterc   N)rU   rT   r   reSecondsReaderfindallrl   MAX_FINITE_TIMEOUT_LIMIT)timeoutvaluetimeoutsecstimeoutvaluelisttimeoutspeclistSRr   s         r+   read_timeout_value_headerr=    s    K#))#.'!'')*,$,,[9F!$i!99!#&&  ( r*   c                    U (       d  gSU;   aT  U R                  5       (       a?  [        US   5      nSnU H  nXb:X  d  US:X  d  M  Sn  O   U(       d  [        [        S5      eSnSU;   a1  U R	                  5       (       a  [        US   5      nU(       a  X:  a  SnSn	SU;   ai  U R                  5       (       aT  [        US   5      nU H>  nXb:X  d  US:X  d  M  US	   S
;   a  U(       d  [        [        S5      e[        [        S5      e   Sn	SU;   a?  U R	                  5       (       a*  [        US   5      n
U
(       a  X:  a  [        [        S5      eU(       a  U	(       d  [        [        S5      eg)a  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_tagrf  
token_listr(  tokenifModifiedSinceFailed	ifmodtimeignoreIfModifiedSinceifunmodtimes              r+   evaluate_http_conditionalsrQ    s   0  '!g&:&:&<&<*7?+CD
E"esl   35WXX "7*w/G/G/I/I%g.F&GH	2$(! "w&7+?+?+A+A*73G+HI
E"esl ,-@1"#46STT,.U    !%!W,1I1I1K1K'0J(KL;6(*W  %:(*UVV
r*   z(\<([^>]+)\>)|(\(([^\)]+)\))z\<([^>]+)\>([^<]+)z\(([^)]+)\)z(\S+)c           	         SU ;   a  gSU ;  a  SU S'   / U S'   gU S   R                  5       nUR                  S5      (       d  SU-   n[        / 5      n/ nSn[        R	                  U5       H  u  pVpxUS:w  a  UnM  / n	S	n
[
        R	                  U5       H  nUR                  5       S
:w  a}  UR                  S5      (       a$  U	R                  U
SUR                  S5      45        OCU	R                  U
SUR                  S5      45        UR                  UR                  S5      5        UR                  5       S
:g  n
M     XB;   a  X$   nO/ nXU'   UR                  U	5        M     X S'   X0S'   [        R                  S[        U5       35        g)zParse 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
)rT   rj   rV   reIfSeparatorr6  reIfTagListContentsupperr   r   r   r   )rf  iftextifDict
ifLockList	resource1	tmpURLVarURLVar_tmpContentVar
contentVarlistTagContentstestflaglistitemlistTags                r+   parse_if_header_dictrg  x  s   
 ')+/'(-/)*Y%%'FS!!"XFJI9F9N9Nv9V5	>?I OH/77
C>>#u,**3//'..%x1FG (..%{HNN44HI #))(..*>?#>>+u4 D " +$+y!NN?+1 :W4 (.#$)3%&MM*76?*;<=
r*   c           	      h   [         R                  SU SU SU S35        X!;   a  X   nOSU;   a  US   nOgU R                  5       nU HQ  nSnU H=  u  pnU
S:X  a  U(       a  XK:H  nOU
S:X  a  U	nOU
S:X  a  X;   nOSnX:H  nU(       a  M;  Sn  O   U(       a  MQ    g   [         R                  S	5        g)
Nztest_if_header_dict(rQ   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    MM(	N3C2j\QRST#	3< ++-!0=,H*X%*:'5
x'%
{*'9
!
$0K;" 1> {# "$ MM- r*   z	audio/oggz	video/oggz
video/webmzapplication/yaml)z.ogaz.oggz.ogvz.webmz.ymlz.yamlc                     [         R                  " U 5      u  pU(       dR  [        R                  R	                  U 5      S   n[
        R                  U5      n[        R                  SU  SU 35        U(       d  SnU$ )zzUse the mimetypes module to lookup the type for an extension.

This function also adds some extensions required for HTML5
rb   z	mimetype(z): zapplication/octet-stream)		mimetypes
guess_typer?  r  r@  _MIME_TYPESr   r   r   )r  mimetype_mimeencodingrA  s       r+   guess_mime_typer{    sg    
 !* 4 4S 9Xggs#A&??3'	#c(45-Or*   )r1  r   )F)r-   N)r(   r  r   collections.abcr   r   rv  r?  rer  r2   r   r6   r   r   email.utilsr   r   hashlibr   pprintr   typingr   r	   r
   urllib.parser   r   r   wsgidav.dav_errorr   r   r   r   r   r   r   r   r   r   wsgidav.xml_toolsr   r   r   r   __docformat__r   r   r   r4   r3   r5   r8   getfilesystemencodingr   public_wsgidav_infopublic_python_infor    r   r<   rA   rC   rE   rJ   rL   rR   r\   rd   r|   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r
  r  r  r  r!  r(  r/  r2  r9  r=  rB  rR  rb  rg  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  rx  r{  r@   s   0r+   <module>r     s  
      	 	  
    -   , ,     V U"  


,
- 3+;+;BQ+?@+?a3q6+?@A..0 
 !.  ~./  eCj T &'
 

 !e   )3 :u :@ $) , $(TE 2pP" (/ c 3 2BBA
"Fyx 9> .  >Bt GT <@ INC  4 C 'S .@ &	 "UTPT$,N )-$  L(GFX  4# #>')c )c )
3 3 3S S T 
:
$ ,1 TD 04U(V@=QJ &+ ",L zz"78 ZZ6 G)^ 3 **0"$$70Sl 

:;ZZ-.
jj(jj* 2jR a5 As   5K