U
    k;Þd`  ã                   @   sö   d Z ddlmZmZmZ ddlmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZmZmZ ddlZddlZddlZddlZddlZdZ e !e"¡Z#dd„ Z$G dd„ de%ƒZ&dS )a  
::

     _      __         _ ___  ___ _   __
    | | /| / /__ ___  (_) _ \/ _ | | / /
    | |/ |/ (_-</ _ `/ / // / __ | |/ /
    |__/|__/___/\_, /_/____/_/ |_|___/
               /___/

WSGI container, that handles the HTTP requests. This object is passed to the
WSGI server and represents our WsgiDAV application to the outside.

On init:

    Use the configuration dictionary to initialize lock manager, property manager,
    domain controller.

    Create a dictionary of share-to-provider mappings.

    Initialize middleware objects and setup the WSGI application stack.

For every request:

    Find the registered DAV provider for the current request.

    Add or modify info in the WSGI ``environ``:

        environ["SCRIPT_NAME"]
            Mount-point of the current share.
        environ["PATH_INFO"]
            Resource path, relative to the mount path.
        environ["wsgidav.provider"]
            DAVProvider object that is registered for handling the current
            request.
        environ["wsgidav.config"]
            Configuration dictionary.
        environ["wsgidav.verbose"]
            Debug level [0-3].

    Log the HTTP request, then pass the request to the first middleware.

    Note: The OPTIONS method for the '*' path is handled directly.

é    )Ú__version__ÚcompatÚutil)ÚDAVProvider)ÚDEFAULT_CONFIG)ÚFilesystemProvider)ÚHTTPAuthenticator)ÚLockManager)ÚLockStorageDict)ÚLockStorageShelve)ÚBaseMiddleware)ÚPropertyManager)ÚShelvePropertyManager)Údynamic_import_classÚdynamic_instantiate_middlewareÚsafe_re_encodeNÚreStructuredTextc           
      C   sÌ   g }d}|D ]}|| kr|  d |¡¡ qdddddddd	d	d
ddddddddddœ}| ¡ D ]R\}}d|krˆ| dd¡\}}| | }	n
| | }	}|	r^||	kr^|  d ||¡¡ q^|rÈtdd |¡ ƒ‚dS )N)Úprovider_mappingzMissing required option '{}'.zhttp_authenticator.accept_basicz http_authenticator.accept_digestzerror_printer.catch_allz$http_authenticator.default_to_digestÚmiddleware_stackz!dir_browser.ms_sharepoint_supportz$http_authenticator.domain_controllerzhotfix.emulate_win32_lastmodznt_dc.preset_domainznt_dc.preset_serverÚlock_managerÚmutable_live_propsÚproperty_managerzhotfix.re_encode_path_infoz&http_authenticator.trusted_auth_headerzhotfix.unquote_path_infozsimple_dc.user_mapping)ZacceptbasicZacceptdigestZcatchallZdefaultdigestzdir_browser.app_classz dir_browser.ms_sharepoint_pluginzdir_browser.ms_sharepoint_urlÚdomain_controllerZdomaincontrollerÚemulate_win32_lastmodz http_authenticator.preset_domainz http_authenticator.preset_serverZlocksmanagerÚmutableLivePropsZpropsmanagerÚre_encode_path_infoÚtrusted_auth_headerÚunquote_path_infoÚuser_mappingÚ.é   z)Deprecated option '{}': use '{}' instead.zInvalid configuration:
  - z
  - T)ÚappendÚformatÚitemsÚsplitÚ
ValueErrorÚjoin)
ÚconfigÚerrorsZmandatory_fieldsÚfieldZdeprecated_fieldsÚoldÚnewÚkÚvÚd© r/   ú#/opt/wsgidav/wsgidav/wsgidav_app.pyÚ_check_configP   sF    ì

r1   c                   @   s.   e Zd Zdd„ Zddd„Zdd„ Zdd	„ Zd
S )Ú
WsgiDAVAppc              	   C   sò  t  t¡| _t | j|¡ | j}t|ƒ | dd¡| _| di ¡}| dd ¡| _	| j	d krbt
j| _	| dd¡| _| d¡}|dkrˆtƒ }td	ƒ}|sœd | _n
t|ƒ| _| d
¡| _| jsÊd | _tdƒ| _n| jdkrÜtƒ | _| d¡| _| di ¡}| jd }i | _d | _| ¡ D ]\}}|  ||¡ qd | _d }| dg ¡}	g }
| | _t|	ƒD ]}d }t
 |¡r€t|ƒ}|| | j|ƒ}n|t|ƒtkrÌt |ƒdks t!‚t"| ¡ ƒd \}}d| ji}t#|||ƒ}n0t$ %|¡røt&|t'ƒsèt!‚|| | j|ƒ}n|}t(|t)ƒr|| _| *¡ }|r\t+t,|dd ƒƒrJ| -¡ rJt. /d 0|¡¡ n|
 1|¡ || _nt. 2d 0|¡¡ qR| t. 3d 0t4tj5t6j6dd¡¡ | jdkr¸t. 3d 0t7 8¡ t7 9¡ ¡¡ | jdkrøt. 3d 0| j¡¡ t. 3d 0| j¡¡ t. 3d 0|¡¡ | jdkr.t. 3d¡ t|
ƒD ]}t. 3d 0|¡¡ q| jdkr„t. 3d¡ | jD ]8}| j| }| :|¡rhd nd!}t. 3d" 0|||¡¡ qJ| d#¡r¦| d$¡s¦t. /d%¡ |rî| j ¡ D ]6\}}| :|¡r¶t. /d& 0|| ;¡ râd'nd(¡¡ q¶d S ))NÚverboseé   Úhotfixesr   r   Fr   Tz/var/tmp/wsgidav.locks.shelver   z/var/tmp/wsgidav.props.shelveÚ
mount_pathÚhttp_authenticatorr   r   r    r   z${application}Úis_disabledz-App {}.is_disabled() returned True: skipping.zCould not add middleware {}.zWsgiDAV/{} Python/{} {})Úaliasedé   z*Default encoding: {!r} (file system: {!r})zLock manager:      {}zProperty manager:  {}zDomain controller: {}zMiddleware stack:z  - {}z"Registered DAV providers by route:z (anonymous)Ú z  - '{}': {}{}Úaccept_basicÚssl_certificatezHBasic authentication is enabled: It is highly recommended to enable SSL.z*Share '{}' will allow anonymous {} access.ÚreadÚwrite)<ÚcopyÚdeepcopyr   r'   r   Údeep_updater1   Úgetr3   r   r   ÚPY3r   r
   r   r   r	   Úprop_managerr   r   r6   Úprovider_mapÚsorted_share_listr#   Úadd_providerr7   ÚapplicationÚreversedÚis_basestringr   ÚtypeÚdictÚlenÚAssertionErrorÚlistr   ÚinspectÚisclassÚ
issubclassr   Ú
isinstancer   Úget_domain_controllerÚcallableÚgetattrr8   Ú_loggerÚwarningr"   r!   ÚerrorÚinfor   ÚPYTHON_VERSIONÚplatformÚsysÚgetdefaultencodingÚgetfilesystemencodingÚis_share_anonymousÚis_readonly)Úselfr'   r5   Zlock_storageÚ	auth_confr   ÚshareÚproviderr   r   Zmw_listÚmwÚappZ	app_classÚnameÚargsÚexpandÚhintr/   r/   r0   Ú__init__‚   sÚ    





 ÿ
ÿ
  
ÿÿ ÿÿ



ÿýÿ ÿÿzWsgiDAVApp.__init__Fc                 C   s,  d|  d¡ }|| jkst‚t |¡r2t||ƒ}nxt|ƒtfkrŒd|krpt|d ƒ}|| 	dg ¡| 	di ¡Ž}qªt|d t
| 	dd¡ƒƒ}nt|ƒttfkrªtd |¡ƒ‚t|tƒsÂtd	 |¡ƒ‚| |¡ | jrÞ| | j¡ | | j¡ | | j¡ || j|< d
d„ | j ¡ D ƒ| _t| jtdd| _|S )z1Add a provider to the provider_map routing table.ú/rf   rj   ÚkwargsÚrootÚreadonlyFz5Provider {}: tuple/list syntax is no longer supportedzInvalid provider {}c                 S   s   g | ]}|  ¡ ‘qS r/   )Úlower)Ú.0Úsr/   r/   r0   Ú
<listcomp>X  s     z+WsgiDAVApp.add_provider.<locals>.<listcomp>T)ÚkeyÚreverse)ÚstriprF   rO   r   rK   r   rL   rM   r   rC   ÚboolrP   Útupler%   r"   rT   r   Úset_share_pathr6   Úset_mount_pathÚset_lock_managerr   Úset_prop_managerrE   ÚkeysrG   ÚsortedrN   )rc   re   rf   rq   Z
prov_classr/   r/   r0   rH   '  s<    

 
ÿ ÿÿ


zWsgiDAVApp.add_providerc                 C   sd   d}|  ¡ }| jD ]4}|dkr(|} qHq||ks>| |d ¡r|} qHq|dkrTdS || j |¡fS )zpGet the registered DAVProvider for a given path.

        Returns:
            tuple: (share, provider)
        Nrn   )NN)rr   rG   Ú
startswithrF   rC   )rc   Úpathre   Z
lower_pathÚrr/   r/   r0   Úresolve_provider]  s    
zWsgiDAVApp.resolve_providerc           	   	   #   s’  ˆ d }ˆj r$t |¡ ¡  }ˆ d< ˆjr8t ˆ d ¡}t |¡s\t d 	|¡¡ t 
|¡}ˆjˆ d< d ˆ d< ˆjˆ d< ˆ |¡\}}|ˆ d< |dksš|s¤|ˆ d< n$ˆ d  |7  < |t|ƒd … ˆ d< t |¡sÖt‚ˆ d dksôˆ d  d¡sôt‚ˆ d d	ksˆ d  d¡rt‚ˆ d dks8ˆ d  d¡s8t‚t ¡ ‰d‡ ‡‡‡fd
d„	}ˆ ˆ |¡}z|D ]}|V  qfW 5 t|dƒrŒ| ¡  X d S )NÚ	PATH_INFOzGot non-native PATH_INFO: {!r}zwsgidav.configzwsgidav.providerzwsgidav.verbosern   ÚSCRIPT_NAMEr;   )r;   rn   c                    sª  i }|D ]0\}}|  ¡ |kr,t d |¡¡ |||  ¡ < qd}| d¡}t|  dd¡d ƒ}ˆ d dkov|d	kov|d
k}	|	rš|dkršt d |¡¡ d}n&t|ƒtk	rÀt d | d¡¡¡ d}t	 
ˆ ¡ t	 ˆ ¡dkrðˆ  d¡sðt d¡ d}|r| d¡dkrt d¡ | d¡ dˆ kr’ˆ d dkr’dd ˆ  d¡ d¡d  d¡dd … ¡ }
ddd„ |D ƒkr’| ddˆ d › d|
› d f¡ ˆjd!krŒˆ  d"¡}|s²d#}g }d$ˆ krÖ| d% ˆ  d$¡¡¡ ˆ  d&d¡dkrþ| d' ˆ  d&¡¡¡ d(ˆ kr| d) ˆ  d(¡¡¡ d*ˆ kr>| d+ ˆ  d*¡¡¡ d,ˆ kr^| d- ˆ  d,¡¡¡ ˆjd!krŠd.ˆ krŠ| d/ ˆ  d.¡¡¡ ˆjd0kr¶d1ˆ kr¶| d2 ˆ  d1¡¡¡ ˆjd0krâd3ˆ krâ| d4 ˆ  d3¡¡¡ ˆjd0krd5ˆ kr| d6 ˆ  d5¡¡¡ ˆjd!kr2| d7 t ¡ ˆ ¡¡ d8 |¡}t d9jˆ  d:d¡|t	 ¡ ˆ  d¡tˆ  d;d¡tjjr|tjjnd<ƒ|| d=¡ t d>t|ƒ ¡ ˆ| ||ƒS )?Nz Duplicate header in response: {}Fzcontent-lengthú r    r   ÚREQUEST_METHODÚHEADéÈ   )éÌ   i0  )Nr;   zIMissing required Content-Length header in {}-response: closing connectionTzDInvalid Content-Length header in response ({!r}): closing connectionzwsgidav.all_input_readz9Input stream not completely consumed: closing connection.Ú
connectionÚclosez"Adding 'Connection: close' header.)Ú
Connectionr   zwsgidav.auth.jwtr;   r   Ú	HTTP_HOSTú:éþÿÿÿz
Set-Cookiec                 S   s   g | ]}|d  ‘qS )r   r/   )rs   Úir/   r/   r0   ru     s     zHWsgiDAVApp.__call__.<locals>._start_response_wrapper.<locals>.<listcomp>zaccess_token=z!;expires=;max-age=2592000;domain=z;path=/r4   zwsgidav.auth.user_namez(anonymous)ÚHTTP_DESTINATIONz	dest="{}"ÚCONTENT_LENGTHz	length={}Ú
HTTP_DEPTHzdepth={}Ú
HTTP_RANGEzrange={}ÚHTTP_OVERWRITEzoverwrite={}ÚHTTP_EXPECTzexpect="{}"r:   ZHTTP_CONNECTIONzconnection="{}"ÚHTTP_USER_AGENTz
agent="{}"ÚHTTP_TRANSFER_ENCODINGztransfer-enc={}zelap={:.3f}secz, z@{addr} - {user} - [{time}] "{method} {path}" {extra} -> {status}ÚREMOTE_ADDRr…   zutf-8)ÚaddrÚuserÚtimeÚmethodr‚   ÚextraÚstatuszRESPONSE HEADERS )rr   rX   rZ   r"   rC   Úintr$   rL   Ústrr   Úread_and_discard_inputÚget_content_lengthrY   r!   r&   r3   rž   r[   Úget_log_timer   r^   ÚstdoutÚencodingÚdebug)r¡   Úresponse_headersÚexc_infoZ
headerDictÚheaderÚvalueZforceCloseConnectionZcurrentContentLengthZ
statusCodeZcontentLengthRequiredÚdomainZuserInfor    ©Úenvironrc   Ústart_responseZ
start_timer/   r0   Ú_start_response_wrapperÆ  s°    
ÿýÿÿÿÿ	
ÿÿ

, 




ÿÿ


þöÿz4WsgiDAVApp.__call__.<locals>._start_response_wrapperr   )N)r   r   Úwsgi_to_bytesÚdecoder   ÚunquoteÚ	is_nativerX   rY   r"   Ú	to_nativer'   r3   r„   rN   rO   r   Úendswithrž   rI   Úhasattrr   )	rc   r°   r±   r‚   re   rf   r²   Úapp_iterr-   r/   r¯   r0   Ú__call__t  sD    





ÿþ
"w
zWsgiDAVApp.__call__N)F)Ú__name__Ú
__module__Ú__qualname__rm   rH   r„   r»   r/   r/   r/   r0   r2      s
    &
6r2   )'Ú__doc__Úwsgidavr   r   r   Úwsgidav.dav_providerr   Úwsgidav.default_confr   Úwsgidav.fs_dav_providerr   Úwsgidav.http_authenticatorr   Zwsgidav.lock_managerr	   Zwsgidav.lock_storager
   r   Úwsgidav.middlewarer   Z!wsgidav.prop_man.property_managerr   r   Zwsgidav.utilr   r   r   r@   rQ   r]   r^   rž   Ú__docformat__Úget_module_loggerr¼   rX   r1   Úobjectr2   r/   r/   r/   r0   Ú<module>   s*   ,
1