U
    ’Áye¦b  ã                   @   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 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)ÚLockStorageRedis)Ú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© r0   ú#/opt/wsgidav/wsgidav/wsgidav_app.pyÚ_check_configQ   sF    ì

r2   c                   @   s.   e Zd Zdd„ Zddd„Zdd„ Zdd	„ Zd
S )Ú
WsgiDAVAppc              	   C   sT  t  t¡| _t | j|¡ | j}t|ƒ | dd¡| _| di ¡}| dd ¡| _	| j	d krbt
j| _	| dd¡| _| d¡}|dkrî| d	d
¡}|dkrÖ| di ¡  ¡ }|s²d|d< | dd ¡ | dd ¡ tf |Ž}n|d
krètdƒ}ntƒ }|súd | _n
t|ƒ| _| d¡| _| js*d | _tdƒ| _n| jdkr>tƒ | _| d¡| _| di ¡}| jd }i | _d | _| ¡ D ]\}}	|  ||	¡ qtd | _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& '|¡rZt(|t)ƒsJt#‚|| | j|ƒ}n|}t*|t+ƒrx|| _| ,¡ }
|r¾t-t.|dd ƒƒr¬| /¡ r¬t0 1d 2|¡¡ n| 3|¡ || _nt0 4d 2|¡¡ q´|
 t0 5d 2t6tj7t8j8dd¡¡ | jd krt0 5d! 2t9 :¡ t9 ;¡ ¡¡ | jdkrZt0 5d" 2| j¡¡ t0 5d# 2| j¡¡ t0 5d$ 2|
¡¡ | jd krt0 5d%¡ t|ƒD ]}t0 5d& 2|¡¡ qx| jdkræt0 5d'¡ | jD ]8}| j| }	|
 <|¡rÊd(nd)}t0 5d* 2||	|¡¡ q¬| d+¡r| d,¡st0 1d-¡ |
rP| j ¡ D ]6\}}	|
 <|¡rt0 1d. 2||	 =¡ rDd/nd0¡¡ qd S )1NÚverboseé   Úhotfixesr   r   Fr   TÚlock_storage_typeZshelveZredisZlock_storage_paramsz /var/run/redis/redis-server.sockZunix_socket_pathÚtypeZ	celery_dbz/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_updater2   Úgetr4   r   r   ÚPY3r   Úpopr   r   r
   r   r	   Úprop_managerr   r   r9   Úprovider_mapÚsorted_share_listr$   Úadd_providerr:   ÚapplicationÚreversedÚis_basestringr   r8   ÚdictÚlenÚAssertionErrorÚlistr   ÚinspectÚisclassÚ
issubclassr   Ú
isinstancer   Úget_domain_controllerÚcallableÚgetattrr;   Ú_loggerÚwarningr#   r"   ÚerrorÚinfor   ÚPYTHON_VERSIONÚplatformÚsysÚgetdefaultencodingÚgetfilesystemencodingÚis_share_anonymousÚis_readonly)Úselfr(   r6   Zlock_storager7   Zredis_paramsÚ	auth_confr   ÚshareÚproviderr   r   Zmw_listÚmwÚappZ	app_classÚnameÚargsÚexpandÚhintr0   r0   r1   Ú__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.ú/ri   rm   ÚkwargsÚrootÚreadonlyFz5Provider {}: tuple/list syntax is no longer supportedzInvalid provider {}c                 S   s   g | ]}|  ¡ ‘qS r0   )Úlower)Ú.0Úsr0   r0   r1   Ú
<listcomp>f  s     z+WsgiDAVApp.add_provider.<locals>.<listcomp>T)ÚkeyÚreverse)ÚstriprJ   rR   r   rO   r   r8   rP   r   rF   ÚboolrS   Útupler&   r#   rW   r   Úset_share_pathr9   Úset_mount_pathÚset_lock_managerr   Úset_prop_managerrI   ÚkeysrK   ÚsortedrQ   )rf   rh   ri   rt   Z
prov_classr0   r0   r1   rL   5  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)
        Nrq   )NN)ru   rK   Ú
startswithrJ   rF   )rf   Úpathrh   Z
lower_pathÚrr0   r0   r1   Úresolve_providerk  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.verboserq   ÚSCRIPT_NAMEr>   )r>   rq   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   r0   )rv   Úir0   r0   r1   rx     s     zHWsgiDAVApp.__call__.<locals>._start_response_wrapper.<locals>.<listcomp>zaccess_token=z!;expires=;max-age=2592000;domain=z;path=/r5   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 )ru   r[   r]   r#   rF   Úintr%   r8   Ústrr   Úread_and_discard_inputÚget_content_lengthr\   r"   r'   r4   r¡   r^   Úget_log_timer   ra   ÚstdoutÚencodingÚdebug)r¤   Úresponse_headersÚexc_infoZ
headerDictÚheaderÚvalueZforceCloseConnectionZcurrentContentLengthZ
statusCodeZcontentLengthRequiredÚdomainZuserInfor£   ©Úenvironrf   Ústart_responseZ
start_timer0   r1   Ú_start_response_wrapperÔ  s°    
ÿýÿÿÿÿ	
ÿÿ

, 




ÿÿ


þöÿz4WsgiDAVApp.__call__.<locals>._start_response_wrapperr   )N)r   r   Úwsgi_to_bytesÚdecoder   ÚunquoteÚ	is_nativer[   r\   r#   Ú	to_nativer(   r4   r‡   rQ   rR   r„   Úendswithr¡   rM   Úhasattrr   )	rf   r³   r´   r…   rh   ri   rµ   Úapp_iterr.   r0   r²   r1   Ú__call__‚  sD    





ÿþ
"w
zWsgiDAVApp.__call__N)F)Ú__name__Ú
__module__Ú__qualname__rp   rL   r‡   r¾   r0   r0   r0   r1   r3   ‚   s
    3
6r3   ))Ú__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   Zwsgidav.lock_storage_redisr   Úwsgidav.middlewarer   Z!wsgidav.prop_man.property_managerr   r   Zwsgidav.utilr   r   r   rC   rT   r`   ra   r¡   Ú__docformat__Úget_module_loggerr¿   r[   r2   Úobjectr3   r0   r0   r0   r1   Ú<module>   s,   ,
1