o
    �õ±j~Ò  ã                   @   s  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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 ddlmZmZ G d	d
„ d
ƒZG dd„ deƒZ		ddd„Z		ddd„Zdd„ Z e!dkr‚e ƒ  dS dS )aO  
WebDAV Server Example

This example demonstrates how to create a fully-featured WebDAV server using the 
HTTPServerHandler class. The server implements the WebDAV protocol (RFC 4918) with
support for:

- File and directory operations (GET, PUT, DELETE, MKCOL)
- WebDAV properties (PROPFIND, PROPPATCH)  
- File locking (LOCK, UNLOCK)
- File copying and moving (COPY, MOVE)
- WebDAV-compliant XML responses
- Integration with file managers and WebDAV clients

Usage:
    python webdavserver.py [directory_path] [host] [port]

Example:
    python webdavserver.py ./webdav-root 127.0.0.1 8080
é    N)ÚPath)ÚdatetimeÚtimezone)ÚElementTree)Úminidom)Ú	UniTargetÚUniProto)ÚHTTPServerHandlerÚ
HTTPServerc                   @   s*   e Zd ZdZddd„Zdd„ Zdd	„ Zd
S )Ú
WebDAVLockz'Represents a WebDAV lock on a resource.é  Ú0c                 C   s2   || _ || _|| _|| _|| _|| _t ¡ | _d S ©N)ÚtokenÚscopeÚtypeÚownerÚtimeoutÚdepthÚtimeÚcreated)Úselfr   r   Ú	type_lockr   r   r   © r   ú‘/root/aizidognhua/tmp/workspace/projects/ec89d86c-575f-41c9-af57-ac45cbdbf775/venv/lib/python3.10/site-packages/asysocks/examples/webdavserver.pyÚ__init__-   s   zWebDAVLock.__init__c                 C   s   t   ¡ | j | jkS r   )r   r   r   )r   r   r   r   Ú
is_expired6   s   zWebDAVLock.is_expiredc                 C   sØ   t jddd�}t  |d¡}t  |d| j› �¡ t  |d¡}t  |d| j› �¡ t  |d¡}| j|_t  |d¡}| j|_t  |d	¡}d
| j› �|_t  |d¡}t  |d¡}	d| j	› �|	_t  |d¡}
t  |
d¡}||_|S )z"Convert lock to WebDAV XML format.zD:activelockúDAV:)Úxmlnsz
D:locktypeúD:zD:lockscopezD:depthzD:ownerz	D:timeoutúSecond-zD:locktokenúD:hrefzopaquelocktoken:z
D:lockroot)
ÚETÚElementÚ
SubElementr   r   r   Útextr   r   r   )r   ÚhrefÚ	lock_elemÚlocktype_elemÚlockscope_elemÚ
depth_elemÚ
owner_elemÚtimeout_elemÚlocktoken_elemÚ	href_elemÚlockroot_elemÚlockroot_hrefr   r   r   Úto_xml9   s$   zWebDAVLock.to_xmlN)r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r1   r   r   r   r   r   *   s
    
	r   c                       s  e Zd ZdZ		dC‡ fdd„	ZdDd	d
„Zdd„ Zdd„ Zdd„ ZdEdd„Z	dEdd„Z
dd„ Zdd„ ZdEdd„Zdd„ Zdd„ ZdEdd „Zd!d"„ Zd#d$„ Zd%d&„ Zd'd(„ Zd)d*„ Zd+d,„ Zd-d.„ Zd/d0„ Zd1d2„ Zd3d4„ Zd5d6„ Zd7d8„ Zd9d:„ Zd;d<„ Zd=d>„ Zd?d@„ Z dAdB„ Z!‡  Z"S )FÚWebDAVHandlerap  
    WebDAV server handler implementing RFC 4918 WebDAV specification.
    
    Features:
    - Complete WebDAV method support (PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK)
    - XML property handling with namespace support
    - File locking mechanism
    - Directory traversal protection
    - MIME type detection
    - WebDAV-compliant error responses
    NTr   éd   c                    s�   t ƒ  ¡  || _|| _|| _|| _|| _i | _dddœ| _| jrDt	j
 | j¡| _t	j
 | j¡s5t	 | j¡ t	j
 | j¡sFtd| j› �ƒ‚dS dS )a’  
        Initialize the WebDAV handler.
        
        Args:
            webdav_root (str): Root directory to serve WebDAV from
            enable_locks (bool): Whether to enable WebDAV locking
            default_lock_timeout (int): Default lock timeout in seconds
            max_depth (int): Maximum depth for PROPFIND operations
            print_cb (callable): Logging callback function
        r   z$http://www.w3.org/XML/1998/namespace)ÚDÚxmlz WebDAV root is not a directory: N)Úsuperr   Úwebdav_rootÚenable_locksÚdefault_lock_timeoutÚ	max_depthÚprint_cbÚlocksÚ
namespacesÚosÚpathÚabspathÚexistsÚmakedirsÚisdirÚ
ValueError)r   r;   r<   r=   r>   r?   ©Ú	__class__r   r   r   d   s$   
þúzWebDAVHandler.__init__Ú c                 Ã   s$   �| j du rdS |   |¡I dH  dS )z-Log a message if print callback is available.N)r?   )r   Úmsgr   r   r   Úprintˆ   s   €
zWebDAVHandler.printc                    sâ   | j sdS |s
| j S | dd¡}g }| d¡D ]%‰ ˆ  ¡ ‰ ˆ r#ˆ dkr$qˆ dkr)qt‡ fdd„dD ƒƒr7 dS | ˆ ¡ q| j }|D ]	‰ tj |ˆ ¡}qBtj 	|¡}ztj 
|| j g¡}|| j krdW dS W |S  typ   Y dS w )	a  
        Sanitize the requested path to prevent directory traversal attacks.
        
        Args:
            path_request (str): The requested file or directory path
            
        Returns:
            str or None: Safe absolute path or None if invalid
        Nú\ú/Ú.z..c                 3   s   � | ]}|ˆ v V  qd S r   r   )Ú.0Úchar©Ú	componentr   r   Ú	<genexpr>©   s   € z/WebDAVHandler._sanitize_path.<locals>.<genexpr>)ú:Ú*ú?ú"ú<ú>ú|)r;   ÚreplaceÚsplitÚstripÚanyÚappendrB   rC   ÚjoinrD   Ú
commonpathrH   )r   Úpath_requestÚnormalized_pathÚpath_componentsÚ	safe_pathÚcommon_pathr   rS   r   Ú_sanitize_pathŽ   s8   

ÿýÿzWebDAVHandler._sanitize_pathc                 C   sV   | j r|sdS ztj || j ¡}|dkrW dS d| tjd¡ W S  ty*   Y dS w )z#Get relative path from WebDAV root.rO   rP   )r;   rB   rC   Úrelpathr]   ÚseprH   )r   Úabsolute_pathÚrel_pathr   r   r   Ú_get_relative_path¾   s   
ÿz WebDAVHandler._get_relative_pathc                 C   s   t  |¡\}}|p
dS )zGet the MIME type for a file.zapplication/octet-stream)Ú	mimetypesÚ
guess_type)r   ÚfilepathÚ	mime_typeÚ_r   r   r   Ú_get_mime_typeÊ   s   zWebDAVHandler._get_mime_typec                 C   ó*   |du rt   ¡ }tj|tjd�}| d¡S )zFormat timestamp as HTTP date.N©Útzz%a, %d %b %Y %H:%M:%S GMT©r   r   Úfromtimestampr   ÚutcÚstrftime©r   Ú	timestampÚdtr   r   r   Ú_format_http_dateÏ   ó   
zWebDAVHandler._format_http_datec                 C   ru   )z"Format timestamp as ISO 8601 date.Nrv   z%Y-%m-%dT%H:%M:%SZrx   r|   r   r   r   Ú_format_iso_dateÖ   r€   zWebDAVHandler._format_iso_datec              	   C   s|   |D ]9\}}|  ¡ dkr;| d¡ ¡ }|  ¡ dkr dS zt|ƒ}|dk r)W  dS t|ƒW   S  ty:   Y  dS w qdS )z$Parse the Depth header from request.s   depthÚasciiÚinfinityr   r   Ú1)ÚlowerÚdecoder_   ÚintÚstrrH   )r   ÚheadersÚnameÚvalueÚ	depth_strr   r   r   r   Ú_parse_depth_headerÝ   s   ÿ÷z!WebDAVHandler._parse_depth_headerc                 C   s@   g }| j  ¡ D ]\}}| ¡ r| |¡ q|D ]}| j |= qdS )zRemove expired locks.N)r@   Úitemsr   ra   )r   Úexpired_pathsrC   Úlockr   r   r   Ú_clean_expired_locksí   s   
€
ÿz"WebDAVHandler._clean_expired_locksc                 C   sD   |   ¡  || jvrdS | j| }|r||jkrdS |jdkr dS dS )z-Check if there are lock conflicts for a path.FÚsharedT)r‘   r@   r   r   )r   rC   r   r�   r   r   r   Ú_check_lock_conflicts÷   s   


z#WebDAVHandler._check_lock_conflictsc                 Ã   sT   �g }	 | j  ¡ I dH }t|tjƒr|jr| |j¡ nt|tjƒr#nnqd |¡S )zRead the full request body.TNó    )	Ú_wrapperÚ
next_eventÚ
isinstanceÚh11ÚDataÚdatara   ÚEndOfMessagerb   )r   Ú
body_partsÚeventr   r   r   Ú_read_request_body  s   €€ø

z WebDAVHandler._read_request_bodyc                 C   sb   |  dd¡ tj|dd�}zt |¡}|jjdd�}dd„ | d	¡D ƒ}d	 |¡W S    | Y S )
z Create a formatted XML response.úxmlns:Dr   Úunicode)Úencodingz  )Úindentc                 S   s   g | ]}|  ¡ r|‘qS r   )r_   )rQ   Úliner   r   r   Ú
<listcomp>(  s    z6WebDAVHandler._create_xml_response.<locals>.<listcomp>Ú
)	Úsetr"   Útostringr   ÚparseStringÚdocumentElementÚtoprettyxmlr^   rb   )r   Úroot_elementÚrough_stringÚreparsedÚprettyÚlinesr   r   r   Ú_create_xml_response  s   
z"WebDAVHandler._create_xml_responsec           
      C   s¢  zÅt  |¡}t j |¡}i }|rd|v r|  |j¡|d< |r"d|v r,t j |¡p)d|d< |r2d|v r;|s;t|jƒ|d< |rAd|v rJ|sJ|  	|¡|d< |rPd|v rX|  
|j¡|d< |r^d|v rmd|j› d	|j› d�}||d< |rsd
|v r~|rzd|d
< nd|d
< |r„d|v r�| jrŒd|d< nd|d< |r–d|v rÃ|  |¡}|| jv r¿| j| }| ¡ s¸|  | |¡¡}	|	|d< |W S d|d< |W S d|d< |W S  tyÐ   i  Y S w )z.Get WebDAV properties for a file or directory.ÚcreationdateÚdisplaynameÚRootÚgetcontentlengthÚgetcontenttypeÚgetlastmodifiedÚgetetagrY   ú-Úresourcetypez<D:collection/>rK   Úsupportedlocka¸  
                        <D:lockentry>
                            <D:lockscope><D:exclusive/></D:lockscope>
                            <D:locktype><D:write/></D:locktype>
                        </D:lockentry>
                        <D:lockentry>
                            <D:lockscope><D:shared/></D:lockscope>
                            <D:locktype><D:write/></D:locktype>
                        </D:lockentry>
                    Úlockdiscovery)rB   ÚstatrC   rG   r�   Úst_ctimeÚbasenamerˆ   Úst_sizert   r   Úst_mtimer<   rn   r@   r   r°   r1   ÚOSError)
r   Ú	file_pathÚrequested_propsr¼   Úis_dirÚpropsÚetagrm   r�   Úlock_xmlr   r   r   Ú_get_file_properties-  sT   





üþÿz"WebDAVHandler._get_file_propertiesc                 Ã   sn   �|   d|j ¡ › �¡I dH  |  ¡ }| g d¢¡ tjd|d�}| j |¡I dH  | j t 	¡ ¡I dH  dS )z7Handle OPTIONS request - advertise WebDAV capabilities.z[WEBDAV] OPTIONS N))ÚAllowsb   OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, PROPFIND, PROPPATCH, COPY, MOVE, MKCOL, LOCK, UNLOCK)ÚDAVs   1, 2)zMS-Author-Vias   DAV©úContent-Lengthó   0éÈ   ©Ústatus_coder‰   )
rM   Útargetr†   Úbasic_headersÚextendr˜   ÚResponser•   Úsendr›   )r   r�   r‰   Úresponser   r   r   Ú
do_OPTIONSr  s   €zWebDAVHandler.do_OPTIONSc                 Ã   s(  �t j |j d¡¡}|  d|› �¡I dH  |  |¡}|s(|  dd¡I dH  dS tj	 
|¡s9|  dd¡I dH  dS |  |j¡}|  ¡ I dH }d}|roz t | d¡¡}| ¡ D ]}|j d¡rhd	d
„ |D ƒ} nqWW n   Y t d¡}	|	 dd¡ |  |	||¡I dH  |dkrÈtj	 |¡rÈz0t |¡D ](}
tj	 ||
¡}|  |	||¡I dH  |dkr¼tj	 |¡r¼|  |	||d¡I dH  q”W n	 tyÇ   Y nw d}||  |	¡7 }| d¡}|  ¡ }| ddtt |ƒƒ d¡fg¡ t!j"d|d�}| j# $|¡I dH  | j# $t!j%|d�¡I dH  | j# $t! &¡ ¡I dH  dS )z6Handle PROPFIND request - get properties of resources.úutf-8z[WEBDAV] PROPFIND Né�  úInvalid pathé”  ú	Not FoundÚpropc                 S   s   g | ]
}|j  d ¡d ‘qS )Ú}éÿÿÿÿ)Útagr^   )rQ   Úchildr   r   r   r¤   �  s    z-WebDAVHandler.do_PROPFIND.<locals>.<listcomp>zD:multistatusrŸ   r   r   rƒ   é   ú'<?xml version="1.0" encoding="utf-8"?>
©úContent-Types   application/xml; charset=utf-8rÌ   r‚   éÏ   rÏ   ©rš   )'ÚurllibÚparseÚunquoterÑ   r†   rM   ri   Ú_serve_errorrB   rC   rE   r�   r‰   rž   r"   Ú
fromstringÚiterrà   Úendswithr#   r¦   Ú_add_propfind_responserG   Úlistdirrb   Ú_add_propfind_recursiveÚPermissionErrorr°   ÚencoderÒ   rÓ   rˆ   Úlenr˜   rÔ   r•   rÕ   r™   r›   )r   r�   rC   rg   r   ÚbodyrÃ   ÚrootÚ	prop_elemÚmultistatusÚitemÚ
child_pathÚxml_contentr‰   rÖ   r   r   r   Údo_PROPFIND‚  sf   €
þ€
€úÿ
þzWebDAVHandler.do_PROPFINDc                 Ã   sp  �t  |d¡}|  |¡}t  |d¡}||_t  |d¡}t  |d¡}|  ||¡}	|	 ¡ D ]�\}
}|s5|dkr¬t  |d|
› �¡}|
dkrf|rfz| ¡ r\t  d|› d	�¡}|D ]}| |¡ qTW q+   ||_Y q+|
d
kr‹|r‹z| ¡ r„t  d|› d	�¡}|D ]}| |¡ q|W q+   Y q+|
dkr§|r§z| ¡ r t  |¡}| |¡ W q+   Y q+t	|ƒ|_q+t  |d¡}d|_dS )z7Add a single resource response to PROPFIND multistatus.z
D:responser!   z
D:propstatúD:proprK   r   r¹   z<temp xmlns:D="DAV:">z</temp>rº   r»   zD:statuszHTTP/1.1 200 OKN)
r"   r$   rn   r%   rÈ   rŽ   r_   rì   ra   rˆ   )r   rø   rÂ   rÃ   Úresponse_elemrm   r.   Úpropstat_elemr÷   rÅ   Ú	prop_nameÚ
prop_valueÚprop_sub_elemÚ	temp_elemrá   Ústatus_elemr   r   r   rï   Æ  sR   €
€
€

€
€
z$WebDAVHandler._add_propfind_responsec              	   Ã   sˆ   �|| j krdS z/t |¡D ]&}tj ||¡}|  |||¡I dH  tj |¡r4|  ||||d ¡I dH  qW dS  tt	fyC   Y dS w )z9Recursively add PROPFIND responses with depth protection.Nrâ   )
r>   rB   rð   rC   rb   rï   rG   rñ   rò   rÁ   )r   rø   Údir_pathrÃ   Úcurrent_depthrù   rú   r   r   r   rñ   ú  s   €
€ûÿz%WebDAVHandler._add_propfind_recursivec                 Ã   sB   �t j |j d¡¡}|  d|› �¡I dH  |  dd¡I dH  dS )z:Handle PROPPATCH request - modify properties of resources.rØ   z[WEBDAV] PROPPATCH Né•  z#Property modification not supported)rè   ré   rê   rÑ   r†   rM   rë   )r   r�   rC   r   r   r   Údo_PROPPATCH	  s   €zWebDAVHandler.do_PROPPATCHc           	   
   Ã   s|  �t j |j d¡¡}|  d|› �¡I dH  |  |¡}|s(|  dd¡I dH  dS tj	 
|¡r9|  dd¡I dH  dS tj	 |¡}tj	 
|¡sP|  dd	¡I dH  dS |  |¡}|  |¡re|  d
d¡I dH  dS z7t |¡ |  d|› �¡I dH  |  ¡ }| d¡ tjd|d�}| j |¡I dH  | j t ¡ ¡I dH  W dS  ty½ } z|  ddt|ƒ› �¡I dH  W Y d}~dS d}~ww )z*Handle MKCOL request - create a directory.rØ   z[WEBDAV] MKCOL NrÙ   rÚ   r  zResource already existsé™  ú Parent collection does not existé§  úResource is lockedz[WEBDAV] Created directory: rË   éÉ   rÏ   éô  zFailed to create directory: )rè   ré   rê   rÑ   r†   rM   ri   rë   rB   rC   rE   Údirnamern   r“   rF   rÒ   ra   r˜   rÔ   r•   rÕ   r›   rÁ   rˆ   )	r   r�   rC   rg   Ú
parent_dirrm   r‰   rÖ   Úer   r   r   Údo_MKCOL  s<   €




*€ÿzWebDAVHandler.do_MKCOLc                 Ã   sª   �t j |j d¡¡}|  d|› �¡I dH  |  |¡}|s(|  dd¡I dH  dS tj	 
|¡s9|  dd¡I dH  dS tj	 |¡rI|  |¡I dH  dS |  ||j¡I dH  dS )z$Handle GET request - download files.rØ   z[WEBDAV] GET NrÙ   rÚ   rÛ   rÜ   )rè   ré   rê   rÑ   r†   rM   ri   rë   rB   rC   rE   rG   Ú_serve_directory_listingÚ_serve_filer‰   )r   r�   rC   rg   r   r   r   Údo_GET=  s   €
zWebDAVHandler.do_GETc           	      Ã   sh  �t j |j d¡¡}|  d|› �¡I dH  |  |¡}|s(|  dd¡I dH  dS tj	 
|¡s9|  dd¡I dH  dS zYt |¡}|  |¡}|  ¡ }| d| d	¡fd
t|jƒ d	¡fd|  |j¡ d	¡fdd|j› d|j› d� d	¡fg¡ tjd|d�}| j |¡I dH  | j t ¡ ¡I dH  W dS  ty³ } z|  ddt|ƒ› �¡I dH  W Y d}~dS d}~ww )z/Handle HEAD request - get headers without body.rØ   z[WEBDAV] HEAD NrÙ   rÚ   rÛ   rÜ   rå   r‚   rÌ   úLast-ModifiedÚETagrY   r¸   rÎ   rÏ   r  zError accessing file: )rè   ré   rê   rÑ   r†   rM   ri   rë   rB   rC   rE   r¼   rt   rÒ   rÓ   ró   rˆ   r¿   r   rÀ   r˜   rÔ   r•   rÕ   r›   rÁ   )	r   r�   rC   rg   r¼   rr   r‰   rÖ   r  r   r   r   Údo_HEADR  s6   €


ü*€ÿzWebDAVHandler.do_HEADc              
   Ã   sæ  �t j |j d¡¡}|  d|› �¡I dH  |  |¡}|s(|  dd¡I dH  dS |  |¡}|  	|¡r=|  dd¡I dH  dS t
j |¡}t
j |¡sT|  dd	¡I dH  dS t
j |¡ }zvt|d
ƒ�*}	 | j ¡ I dH }t|tjƒr{|jrz| |j¡ nt|tjƒr‚nnqcW d  ƒ n1 sŽw   Y  |  d|ršdnd› d|› �¡I dH  |r©dnd}|  ¡ }	|	 d¡ tj||	d�}
| j |
¡I dH  | j t ¡ ¡I dH  W dS  tyò } z|  ddt|ƒ› �¡I dH  W Y d}~dS d}~ww )z)Handle PUT request - upload/create files.rØ   z[WEBDAV] PUT NrÙ   rÚ   r  r  r	  r
  ÚwbTz	[WEBDAV] ÚCreatedÚUpdatedz file: r  éÌ   rË   rÏ   r  zFailed to write file: )rè   ré   rê   rÑ   r†   rM   ri   rë   rn   r“   rB   rC   r  rE   Úopenr•   r–   r—   r˜   r™   rš   Úwriter›   rÒ   ra   rÔ   rÕ   rÁ   rˆ   )r   r�   rC   rg   rm   r  Úis_new_fileÚfrÐ   r‰   rÖ   r  r   r   r   Údo_PUTs  sR   €


€ø€ÿ$
*€ÿzWebDAVHandler.do_PUTc           	   
   Ã   s–  �t j |j d¡¡}|  d|› �¡I dH  |  |¡}|s(|  dd¡I dH  dS tj	 
|¡s9|  dd¡I dH  dS |  |¡}|  |¡rN|  dd	¡I dH  dS z[tj	 |¡rjd
dl}| |¡ |  d|› �¡I dH  nt |¡ |  d|› �¡I dH  || jv rƒ| j|= |  ¡ }| d¡ tjd|d�}| j |¡I dH  | j t ¡ ¡I dH  W dS  tyÊ } z|  ddt|ƒ› �¡I dH  W Y d}~dS d}~ww )z5Handle DELETE request - delete files and directories.rØ   z[WEBDAV] DELETE NrÙ   rÚ   rÛ   rÜ   r  r  r   z[WEBDAV] Deleted directory: z[WEBDAV] Deleted file: rË   r  rÏ   r  zFailed to delete: )rè   ré   rê   rÑ   r†   rM   ri   rë   rB   rC   rE   rn   r“   rG   ÚshutilÚrmtreeÚremover@   rÒ   ra   r˜   rÔ   r•   rÕ   r›   rÁ   rˆ   )	r   r�   rC   rg   rm   r"  r‰   rÖ   r  r   r   r   Ú	do_DELETE¦  s@   €






*€ÿzWebDAVHandler.do_DELETEc              
   Ã   s‚  �t j |j d¡¡}|  d|› �¡I dH  d}d}|jD ]#\}}| ¡ dkr1t j | d¡¡}q| ¡ dkr@| d¡ ¡ dk}q|sN|  	d	d
¡I dH  dS |  
|¡}|  
|¡}|r\|sg|  	d	d¡I dH  dS tj |¡sx|  	dd¡I dH  dS tj |¡}	|	r�|s�|  	dd¡I dH  dS |  |¡}
|  |
¡r¢|  	dd¡I dH  dS z|tj |¡rÉddl}|	r´| |¡ | ||¡ |  d|› d|› �¡I dH  n)ddl}tj |¡}tj |¡sÞt |¡ | ||¡ |  d|› d|› �¡I dH  |	rödnd}|  ¡ }| d¡ tj||d�}| j |¡I dH  | j t ¡ ¡I dH  W dS  t�y@ } z|  	ddt|ƒ› �¡I dH  W Y d}~dS d}~ww )z%Handle COPY request - copy resources.rØ   z[WEBDAV] COPY NTó   destinationó	   overwriter‚   ÚTrÙ   úDestination header requiredrÚ   rÛ   úSource not foundéœ  ú)Destination exists and overwrite is falser  zDestination is lockedr   z[WEBDAV] Copied directory: ú -> z[WEBDAV] Copied file: r  r  rË   rÏ   r  zFailed to copy: ) rè   ré   rê   rÑ   r†   rM   r‰   r…   Úupperrë   ri   rB   rC   rE   rn   r“   rG   r"  r#  Úcopytreer  rF   Úcopy2rÒ   ra   r˜   rÔ   r•   rÕ   r›   rÁ   rˆ   )r   r�   rC   ÚdestinationÚ	overwriterŠ   r‹   Úsafe_sourceÚ	safe_destÚdest_existsÚrel_destr"  r  rÐ   r‰   rÖ   r  r   r   r   Údo_COPYÔ  sj   €€






*€ÿzWebDAVHandler.do_COPYc              
   Ã   s’  �t j |j d¡¡}|  d|› �¡I dH  d}d}|jD ]#\}}| ¡ dkr1t j | d¡¡}q| ¡ dkr@| d¡ ¡ dk}q|sN|  	d	d
¡I dH  dS |  
|¡}|  
|¡}|r\|sg|  	d	d¡I dH  dS tj |¡sx|  	dd¡I dH  dS tj |¡}	|	r�|s�|  	dd¡I dH  dS |  |¡}
|  |¡}|  |
¡s¡|  |¡r¬|  	dd¡I dH  dS zztj |¡}tj |¡s¾t |¡ |	rÕtj |¡rÐddl}| |¡ nt |¡ t ||¡ |  d|› d|› �¡I dH  |
| jv rú| j|
 | j|< | j|
= |	rþdnd}|  ¡ }| d¡ tj||d�}| j |¡I dH  | j t ¡ ¡I dH  W dS  t�yH } z|  	ddt |ƒ› �¡I dH  W Y d}~dS d}~ww )z,Handle MOVE request - move/rename resources.rØ   z[WEBDAV] MOVE NTr&  r'  r‚   r(  rÙ   r)  rÚ   rÛ   r*  r+  r,  r  r  r   z[WEBDAV] Moved: r-  r  r  rË   rÏ   r  zFailed to move: )!rè   ré   rê   rÑ   r†   rM   r‰   r…   r.  rë   ri   rB   rC   rE   rn   r“   r  rF   rG   r"  r#  r$  Úrenamer@   rÒ   ra   r˜   rÔ   r•   rÕ   r›   rÁ   rˆ   )r   r�   rC   r1  r2  rŠ   r‹   r3  r4  r5  Ú
rel_sourcer6  r  r"  rÐ   r‰   rÖ   r  r   r   r   Údo_MOVE  sn   €€







*€ÿzWebDAVHandler.do_MOVEc              
   Ã   s&  �| j s|  dd¡I dH  dS tj |j d¡¡}|  d|› �¡I dH  |  |¡}|s6|  dd¡I dH  dS |  	|¡}|  
¡ I dH }|sO|  dd¡I dH  dS �zt | d¡¡}d	}d
}d}	| j}
| ¡ D ](}|j d	¡rqd	}qf|j d¡rzd}qf|j d
¡rƒd
}qf|j d¡rŽ|jp�d}	qf|jD ](\}}| ¡ dkrº| d¡}| d¡rºz
t|dd… ƒ}
W q’ ty¹   Y q’w q’|  |¡rÌ|  dd¡I dH  W dS tt ¡ ƒ}t||||	|
ƒ}|| j|< |  d|› d|› �¡I dH  t d¡}| dd¡ t |d¡}|  | !|¡¡ d}||  "|¡7 }| #d¡}|  $¡ }| %ddtt&|ƒƒ #d¡fdd|› d� #d¡fg¡ t'j(d |d!�}| j) *|¡I dH  | j) *t'j+|d"�¡I dH  | j) *t' ,¡ ¡I dH  W dS  tj-�yq   |  dd#¡I dH  Y dS  t.�y’ } z|  d$d%t|ƒ› �¡I dH  W Y d}~dS d}~ww )&z%Handle LOCK request - lock resources.r  úLocking not supportedNrØ   z[WEBDAV] LOCK rÙ   rÚ   zLock request body requiredÚ	exclusiver  Úunknownr’   r   s   timeoutr‚   r    é   r  zResource already lockedz[WEBDAV] Created lock z on rý   rŸ   r   zD:lockdiscoveryrã   rä   rÌ   z
Lock-Tokenú<opaquelocktoken:r[   rÎ   rÏ   rç   zInvalid XML in lock requestr  zLock error: )/r<   rë   rè   ré   rê   rÑ   r†   rM   ri   rn   rž   r"   rì   r=   rí   rà   rî   r%   r‰   r…   Ú
startswithr‡   rH   r“   rˆ   ÚuuidÚuuid4r   r@   r#   r¦   r$   ra   r1   r°   ró   rÒ   rÓ   rô   r˜   rÔ   r•   rÕ   r™   r›   Ú
ParseErrorÚ	Exception)r   r�   rC   rg   rm   rõ   rö   Ú
lock_scopeÚ	lock_typer   r   ÚelemrŠ   r‹   Útimeout_strÚ
lock_tokenr�   r÷   Úlockdiscovery_elemrû   r‰   rÖ   r  r   r   r   Údo_LOCKj  sŽ   €


€

ÿ€



ý*€ÿzWebDAVHandler.do_LOCKc                 Ã   s˜  �| j s|  dd¡I dH  dS tj |j d¡¡}|  d|› �¡I dH  |  |¡}|s6|  dd¡I dH  dS |  	|¡}d}|j
D ]!\}}| ¡ dkra| d	¡}| d
¡r_| d¡r_|dd… } nq@|so|  dd¡I dH  dS || jvr|  dd¡I dH  dS | j| }	|	j|kr”|  dd¡I dH  dS | j|= |  d|› d|› �¡I dH  |  ¡ }
|
 d¡ tjd|
d�}| j |¡I dH  | j t ¡ ¡I dH  dS )z)Handle UNLOCK request - unlock resources.r  r;  NrØ   z[WEBDAV] UNLOCK rÙ   rÚ   s
   lock-tokenr‚   r?  r[   é   rß   zLock-Token header requiredr	  zResource not lockedi“  zInvalid lock tokenz[WEBDAV] Removed lock z from rË   r  rÏ   )r<   rë   rè   ré   rê   rÑ   r†   rM   ri   rn   r‰   r…   r@  rî   r@   r   rÒ   ra   r˜   rÔ   r•   rÕ   r›   )r   r�   rC   rg   rm   rI  rŠ   r‹   Ú	token_strr�   r‰   rÖ   r   r   r   Ú	do_UNLOCKÅ  sH   €


û



zWebDAVHandler.do_UNLOCKc                 Ã   s„  ��zt j |¡}|  |¡}t  |¡}d}|D ]\}}| ¡ dkr(| d¡} nqd}	|d }
d}|rf| d¡rfz"|dd… }d	|v rY| d	d¡\}}|rQt	|ƒ}	|rWt	|ƒ}
d
}W n t
tfye   Y nw |
|	 d }|  ¡ }| d| d¡fdt|ƒ d¡fdd|  |j¡ d¡fdd|j› d	|j› d� d¡fg¡ |d
kr´| dd|	› d	|
› d|› � d¡f¡ tj||d�}| j |¡I dH  d}d}t|dƒ�<}|	dkr×| |	¡ ||k �rt||| ƒ}| |¡}|sën| j tj|d�¡I dH  |t|ƒ7 }||k sÜW d  ƒ n	1 �sw   Y  | j t ¡ ¡I dH  W dS  t�yA } z|   ddt|ƒ› �¡I dH  W Y d}~dS d}~ww )z Serve a file with range support.Ns   ranger‚   r   râ   rÎ   zbytes=é   r¸   éÎ   rå   rÌ   )zAccept-Rangess   bytesr  r  rY   zContent-Rangezbytes rO   rÏ   i   Úrbrç   r  zError serving file: )!rB   rC   Úgetsizert   r¼   r…   r†   r@  r^   r‡   rH   Ú
IndexErrorrÒ   rÓ   ró   rˆ   r   rÀ   r¿   ra   r˜   rÔ   r•   rÕ   r  ÚseekÚminÚreadr™   rô   r›   rÁ   rë   )r   rÂ   Úrequest_headersÚ	file_sizerr   r¼   Úrange_headerrŠ   r‹   Ú
start_byteÚend_byterÐ   Ú
range_specÚstartÚendÚcontent_lengthr‰   rÖ   Ú
chunk_sizeÚ
bytes_sentr   Ú	read_sizeÚchunkr  r   r   r   r  ù  sz   €


þ€ÿû&


ø€ü*€ÿzWebDAVHandler._serve_filec                 Ã   sð  �zÕ|   |¡}dt |¡› dt |¡› d�}|dkr3d | d¡ d¡dd… ¡p*d}|d|› d�7 }tt |¡ƒD ]T}tj	 ||¡}t 
|¡}tj	 |¡r^d	}d
}	| d¡d | d }
nd}t|jƒ}	| d¡d | }
|  |j¡}|dt |
¡› dt |¡› d|› d|	› d|› d�7 }q:|d7 }| d¡}|  ¡ }| ddtt|ƒƒ d¡fg¡ tjd|d�}| j |¡I dH  | j tj|d�¡I dH  | j t ¡ ¡I dH  W dS  ty÷ } z|  ddt|ƒ› �¡I dH  W Y d}~dS d}~ww )z&Serve a simple HTML directory listing.z;<!DOCTYPE html>
<html>
<head>
    <title>WebDAV Directory: aº  </title>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        h1 { color: #333; }
        table { border-collapse: collapse; width: 100%; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #f2f2f2; }
        a { text-decoration: none; color: #0066cc; }
        a:hover { text-decoration: underline; }
    </style>
</head>
<body>
    <h1>WebDAV Directory: z™</h1>
    <table>
        <tr>
            <th>Name</th>
            <th>Type</th>
            <th>Size</th>
            <th>Modified</th>
        </tr>
rO   Nrß   z'
        <tr>
            <td><a href="zj">../</a></td>
            <td>Directory</td>
            <td>-</td>
            <td>-</td>
        </tr>
Ú	Directoryr¸   ÚFilez">z</a></td>
            <td>z</td>
            <td>z</td>
        </tr>
zZ
    </table>
    <p><small>WebDAV Server powered by asysocks</small></p>
</body>
</html>
rØ   ©rå   s   text/html; charset=utf-8rÌ   r‚   rÎ   rÏ   rç   r  zError listing directory: )rn   ÚhtmlÚescaperb   Úrstripr^   ÚsortedrB   rð   rC   r¼   rG   rˆ   r¿   r   rÀ   ró   rÒ   rÓ   rô   r˜   rÔ   r•   rÕ   r™   r›   rÁ   rë   )r   r  rm   Úhtml_contentÚparent_pathrù   Ú	item_pathÚ	item_statÚ	item_typeÚ	item_sizeÚitem_urlÚmodifiedrõ   r‰   rÖ   r  r   r   r   r  A  sd   €
ýñ"
þ


þþýüû	
þ*€ÿz&WebDAVHandler._serve_directory_listingc              
   Ã   sâ   �zQd|› d|› dt  |¡› d� d¡}|  ¡ }| ddtt|ƒƒ d¡fg¡ tj||d	�}| j	 
|¡I d
H  | j	 
tj|d�¡I d
H  | j	 
t ¡ ¡I d
H  W d
S  typ } z|  d|› �¡I d
H  W Y d
}~d
S d
}~ww )zServe an error response.z6<!DOCTYPE html>
<html>
<head>
    <title>WebDAV Error z&</title>
</head>
<body>
    <h1>Error z</h1>
    <p>zY</p>
    <hr>
    <p><small>WebDAV Server powered by asysocks</small></p>
</body>
</html>rØ   rf  rÌ   r‚   rÏ   Nrç   zError serving error response: )rg  rh  ró   rÒ   rÓ   rˆ   rô   r˜   rÔ   r•   rÕ   r™   r›   rD  rM   )r   rÐ   Úmessagerõ   r‰   rÖ   r  r   r   r   rë   š  s0   €ýúùõþ$€ÿzWebDAVHandler._serve_error)NTr   r7   N)rK   r   )#r2   r3   r4   r5   r   rM   ri   rn   rt   r   r�   r�   r‘   r“   rž   r°   rÈ   r×   rü   rï   rñ   r  r  r  r  r!  r%  r7  r:  rK  rN  r  r  rë   Ú__classcell__r   r   rI   r   r6   W   sD    ÿ
$0




ED4	+!3.HN[4HYr6   Tr   c              
   ƒ   sh   �z‡ ‡‡‡fdd„}t || ˆd�}tdƒ | ¡ I dH W S  ty3 } z
d|fW  Y d}~S d}~ww )a[  
    Run the WebDAV server from a target.
    
    Args:
        target: Server target configuration
        webdav_root (str): Root directory for WebDAV operations
        log_callback: Logging callback function
        enable_locks (bool): Whether to enable WebDAV locking
        default_lock_timeout (int): Default lock timeout in seconds
    c                      s   t ˆˆˆ ˆd�S )N)r<   r=   r?   )r6   r   ©r=   r<   Úlog_callbackr;   r   r   Ú<lambda>Æ  s    üz/run_webdav_server_from_target.<locals>.<lambda>)rv  z.WebDAV server starting... Press Ctrl+C to stopN)r
   rM   ÚserverD  )rÑ   r;   rv  r<   r=   Úhandler_factoryÚserverr  r   ru  r   Úrun_webdav_server_from_target¹  s   €€ÿr{  ú	127.0.0.1é�  Fc              
   Ã   sn  �z¨zsd}|rdd„ }| r#t d|› d|› �ƒ t dtj | ¡› �ƒ nt d|› d|› d�ƒ |r4t dƒ t d	ƒ t d
|r>dnd› �ƒ |rMt d|› d�ƒ t||tjƒ}t|| |||d�I dH \}}	t d|› �ƒ |	duro|	‚|I dH  W n% ty‚   t dƒ Y n t	yš }
 zt d|
› �ƒ W Y d}
~
nd}
~
ww W |dur¤| 
¡  t dƒ dS |dur²| 
¡  t dƒ w )ad  
    Run the WebDAV server.
    
    Args:
        webdav_root (str): Root directory for WebDAV operations
        host (str): Host to bind to
        port (int): Port to bind to
        debug (bool): Enable debug logging
        enable_locks (bool): Whether to enable WebDAV locking
        default_lock_timeout (int): Default lock timeout in seconds
    Nc                 Ó   s   �t d| › �ƒ d S )Nz[WEBDAV-SERVER] )rM   )rL   r   r   r   rv  ã  s   €z'run_webdav_server.<locals>.log_callbackzStarting WebDAV server on rV   zWebDAV root directory: z (no root directory)z+Debug mode enabled - verbose logging activezWebDAV features:z  - File locking: ÚEnabledÚDisabledz  - Default lock timeout: ú seconds)r;   rv  r<   r=   zServer task: ú
WebDAV server stopped by userzServer error: zWebDAV server stopped)rM   rB   rC   rD   r   r   Ú
SERVER_TCPr{  ÚKeyboardInterruptrD  Úcancel)r;   ÚhostÚportÚdebugr<   r=   rv  rÑ   Úserver_taskÚerrr  r   r   r   Úrun_webdav_serverÓ  sP   €û€ÿ€þ
rŠ  c               
   C   s&  ddl } ddl}| jd| jdd�}|jdddd	� |jd
dddd� |jddtddd� |jddddd� |jdddd� |jdtddd� |jddd d!d"� | ¡ }|jr¥tj	 
|j¡s�td#|j› �ƒ zt |j¡ W n7 ty� } ztd$|j› d%|› �ƒ | d&¡ W Y d}~nd}~ww tj	 |j¡s¥td'|j› d(�ƒ | d&¡ |jd&k s¯|jd)kr¼td*|j› �ƒ | d&¡ |jd&k rÎtd+|j› �ƒ | d&¡ td,ƒ td-ƒ |jrætd.tj	 |j¡› �ƒ ntd/ƒ td0|j› d1|j› �ƒ |jrýtd2ƒ td3|j�rd4nd5› �ƒ |j�std6|j› d7�ƒ td-ƒ td8ƒ td9|j› d1|j› d:�ƒ td;|j› d1|j› d:�ƒ td<ƒ td=ƒ td>ƒ td?ƒ td-ƒ zt t|j|j|j|j|j |jd@�¡ W dS  t�ys   tdAƒ Y dS  t�y’ } ztdB|› �ƒ | d&¡ W Y d}~dS d}~ww )Cz1
    Main entry point for the WebDAV server.
    r   Nz9Asysocks WebDAV Server - RFC 4918 compliant WebDAV serveru¸  
Examples:
  %(prog)s                                    # Start server on 127.0.0.1:8080 (no root)
  %(prog)s /home/user/webdav                 # Serve WebDAV from directory
  %(prog)s /home/user/webdav --host 0.0.0.0  # Bind to all interfaces
  %(prog)s /home/user/webdav --port 9000     # Use custom port
  %(prog)s /home/user/webdav --debug         # Enable debug logging
  %(prog)s /home/user/webdav --no-locks      # Disable file locking
  %(prog)s --help                           # Show this help message

WebDAV Features:
  â€¢ RFC 4918 compliant WebDAV implementation
  â€¢ File and directory operations (GET, PUT, DELETE, MKCOL)
  â€¢ Property queries and modification (PROPFIND, PROPPATCH)
  â€¢ Resource copying and moving (COPY, MOVE)
  â€¢ File locking and unlocking (LOCK, UNLOCK)
  â€¢ Directory traversal protection
  â€¢ Integration with file managers and WebDAV clients
  â€¢ Range request support for large files

Client Compatibility:
  â€¢ Windows Explorer (Map Network Drive)
  â€¢ macOS Finder (Connect to Server)
  â€¢ Linux file managers (Nautilus, Dolphin, etc.)
  â€¢ WebDAV command-line tools (cadaver, davfs2)
  â€¢ Programming libraries (Python requests-webdav, etc.)
        )ÚdescriptionÚformatter_classÚepilogÚ	directoryrX   z WebDAV root directory (optional))ÚnargsÚhelpz--hostz-Hr|  z$Host to bind to (default: 127.0.0.1))Údefaultr�  z--portz-pr}  zPort to bind to (default: 8080))r   r‘  r�  z--debugz-dÚ
store_truez5Enable debug logging (shows detailed server activity))Úactionr�  z
--no-locksz#Disable WebDAV file locking supportz--lock-timeoutr   z/Default lock timeout in seconds (default: 3600)z	--versionz-vÚversionzAsysocks WebDAV Server 1.0.0)r“  r”  z Creating WebDAV root directory: z Error: Cannot create directory 'z': râ   zError: 'z' is not a directoryiÿÿ  z-Error: Port must be between 1 and 65535, got z3Error: Lock timeout must be at least 1 second, got zAsysocks WebDAV Serverz2==================================================zWebDAV Root: z$WebDAV Root: None (server-only mode)zAddress: http://rV   zDebug: EnabledzFile Locking: r  r~  zLock Timeout: r€  z
WebDAV URLs:z  Web Browser: http://rO   z  WebDAV URL:  http://z
Client Setup Examples:z<  Windows Explorer: Map Network Drive -> http://server:port/z>  macOS Finder: Go -> Connect to Server -> http://server:port/z8  Linux: davfs2, cadaver, or file manager WebDAV support)r<   r=   r�  zFailed to start WebDAV server: )ÚargparseÚsysÚArgumentParserÚRawDescriptionHelpFormatterÚadd_argumentr‡   Ú
parse_argsrŽ  rB   rC   rE   rM   rF   rÁ   ÚexitrG   r†  Úlock_timeoutrD   r…  r‡  Úno_locksÚasyncioÚrunrŠ  rƒ  rD  )r•  r–  ÚparserÚargsr  r   r   r   Úmain  sÈ   ý ýýüýýüý€þ



ú€þr¢  Ú__main__)NNTr   )Nr|  r}  FTr   )"r5   rž  rB   Úurllib.parserè   ro   rg  r˜   ÚtempfileÚrerA  r   ÚjsonÚpathlibr   r   r   Ú	xml.etreer   r"   Úxml.domr   Úasysocks.unicomm.common.targetr   r   Ú0asysocks.unicomm.protocol.server.http.httpserverr	   r
   r   r6   r{  rŠ  r¢  r2   r   r   r   r   Ú<module>   sN   -        j
ÿ
ÿ8 
ÿ