22import urllib .parse
33from collections .abc import Callable
44from dataclasses import dataclass , field
5+ from logging import getLogger
56from pyexpat import ExpatError
67from uuid import UUID
78
1819 DAVPropertyPatches ,
1920 DAVUser ,
2021)
21- from asgi_webdav .helpers import dav_xml2dict , receive_all_data_in_one_call
22+ from asgi_webdav .helpers import (
23+ get_dav_property_data_from_xml ,
24+ receive_all_data_in_one_call ,
25+ )
26+
27+ logger = getLogger (__name__ )
28+
29+
30+ _XML_NAME_SPACE_TAG = "@xmlns"
2231
2332
2433@dataclass
@@ -325,7 +334,6 @@ def _cut_ns_key(ns_key: str) -> tuple[str, str]:
325334 return ns_key [:index ], ns_key [index + 1 :]
326335
327336 async def _parser_body_propfind (self ) -> bool :
328- self .body = await receive_all_data_in_one_call (self .receive )
329337 """
330338 A client may choose not to submit a request body. An empty PROPFIND
331339 request body MUST be treated as if it were an 'allprop' request.
@@ -334,25 +342,24 @@ async def _parser_body_propfind(self) -> bool:
334342 # allprop
335343 return True
336344
337- data = dav_xml2dict (self .body )
338- if data is None :
345+ data = get_dav_property_data_from_xml (self .body , "propfind" )
346+ if not data :
339347 return False
340348
341- find_symbol = "DAV::propfind"
342- if "propname" in data [find_symbol ]:
349+ if "propname" in data :
343350 self .propfind_only_fetch_property_name = True
344351 return True
345352
346- if "DAV::allprop" in data [ find_symbol ] :
353+ if "DAV::allprop" in data :
347354 return True
348355 else :
349356 self .propfind_fetch_all_property = False
350357
351- if "DAV::prop" not in data [ find_symbol ] :
358+ if "DAV::prop" not in data :
352359 # TODO error
353360 return False
354361
355- for ns_key in data [find_symbol ][ "DAV::prop" ]:
362+ for ns_key in data ["DAV::prop" ]:
356363 ns , key = self ._cut_ns_key (ns_key )
357364 if key in DAV_PROPERTY_BASIC_KEYS :
358365 self .propfind_basic_keys .add (key )
@@ -365,33 +372,42 @@ async def _parser_body_propfind(self) -> bool:
365372 return True
366373
367374 async def _parser_body_proppatch (self ) -> bool :
368- self .body = await receive_all_data_in_one_call (self .receive )
369- data = dav_xml2dict (self .body )
370- if data is None :
375+ data = get_dav_property_data_from_xml (self .body , "propertyupdate" )
376+ if not data :
371377 return False
372378
373- update_symbol = "DAV::propertyupdate"
374- for action in data [update_symbol ]:
375- _ , key = self ._cut_ns_key (action )
376- if key == "set" :
379+ for action , action_data in data .items ():
380+ if action == _XML_NAME_SPACE_TAG :
381+ continue
382+
383+ _ , action_method = self ._cut_ns_key (action )
384+ if action_method == "set" :
377385 method = True
378386 else :
387+ # remove
379388 method = False
380389
381- for item in data [update_symbol ][action ]:
382- if isinstance (item , dict ):
383- ns_key , value = item ["DAV::prop" ].popitem ()
384- else :
385- ns_key , value = data [update_symbol ][action ][item ].popitem ()
386- if isinstance (value , dict ):
387- # value namespace: drop namespace info # TODO ???
388- value , _ = value .popitem ()
389- _ , value = self ._cut_ns_key (value )
390- # value = "<{} xmlns='{}'>".format(vns_key, vns_ns)
390+ if isinstance (action_data , dict ):
391+ # 当 action 只有一条的时候, actions_data 是一个 dict, 需要转换为 list 以便后续处理
392+ action_data = [action_data ]
391393
394+ for action_item in action_data :
395+
396+ ns_key , dav_prop_data = action_item ["DAV::prop" ].popitem ()
392397 ns , key = self ._cut_ns_key (ns_key )
398+
399+ # value = value.get("#text")
400+ value = None
401+ for prop_key , prop_value in dav_prop_data .items ():
402+ if prop_key == _XML_NAME_SPACE_TAG :
403+ continue
404+ if prop_key == "#text" :
405+ value = prop_value
406+ else :
407+ _ , value = self ._cut_ns_key (prop_key )
408+
393409 if not isinstance (value , str ):
394- value = str (value )
410+ value = str (value ) # TODO: 可能不需要转换?
395411
396412 self .proppatch_entries .append (
397413 DAVPropertyPatches ([DAVPropertyIdentity ((ns , key )), value , method ])
@@ -400,36 +416,39 @@ async def _parser_body_proppatch(self) -> bool:
400416 return True
401417
402418 async def _parser_body_lock (self ) -> bool :
403- self .body = await receive_all_data_in_one_call (self .receive )
404419 if len (self .body ) == 0 :
405420 # LOCK accept empty body
406421 return True
407422
408- data = dav_xml2dict (self .body )
409- if data is None :
423+ data = get_dav_property_data_from_xml (self .body , "lockinfo" )
424+ if not data :
410425 return False
411426
412- if "DAV::exclusive" in data ["DAV::lockinfo" ][ "DAV:: lockscope" ]:
427+ if "DAV::exclusive" in data ["DAV::lockscope" ]:
413428 self .lock_scope = DAVLockScope .exclusive
414429 else :
415430 self .lock_scope = DAVLockScope .shared
416431
417- lock_owner = data ["DAV::lockinfo" ][ "DAV:: owner" ]
432+ lock_owner = data ["DAV::owner" ]
418433 self .lock_owner = str (lock_owner )
419434 return True
420435
421436 async def parser_body (self ) -> bool :
422- if self .method == DAVMethod .PROPFIND :
423- self .body_is_parsed_success = await self ._parser_body_propfind ()
437+ match self .method :
438+ case DAVMethod .PROPFIND :
439+ self .body = await receive_all_data_in_one_call (self .receive )
440+ self .body_is_parsed_success = await self ._parser_body_propfind ()
424441
425- elif self .method == DAVMethod .PROPPATCH :
426- self .body_is_parsed_success = await self ._parser_body_proppatch ()
442+ case DAVMethod .PROPPATCH :
443+ self .body = await receive_all_data_in_one_call (self .receive )
444+ self .body_is_parsed_success = await self ._parser_body_proppatch ()
427445
428- elif self .method == DAVMethod .LOCK :
429- self .body_is_parsed_success = await self ._parser_body_lock ()
446+ case DAVMethod .LOCK :
447+ self .body = await receive_all_data_in_one_call (self .receive )
448+ self .body_is_parsed_success = await self ._parser_body_lock ()
430449
431- else :
432- self .body_is_parsed_success = False
450+ case _ :
451+ self .body_is_parsed_success = False
433452
434453 return self .body_is_parsed_success
435454
0 commit comments