U
    ucT                     @   s   d dl m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
mZ dddZed	ZG d
d dZG dd dZG dd deZG dd deZdS )    )dequeN   )ReadOnlyFileBasedBuffer)build_http_dateloggerqueue_loggerCONTENT_LENGTHCONTENT_TYPE)r   r	   )
connection
keep-alivezproxy-authenticatezproxy-authorizationteZtrailersztransfer-encodingupgradec                   @   sR   e Zd ZdZdZdZeZeZdd Zdd Z	dd Z
d	d
 Zdd ZdddZdS )ThreadedTaskDispatcherz6A Task Dispatcher that creates a thread for each task.r   c                 C   s:   t  | _t | _t | _t| j| _t| j| _	d S N)
setthreadsr   queue	threadingLocklock	Conditionqueue_cvthread_exit_cvself r   1/tmp/pip-unpacked-wheel-yalm6hg1/waitress/task.py__init__3   s
    
zThreadedTaskDispatcher.__init__c                 C   s*   t j|d| |fd}d|_|  d S )Nz	waitress-)targetnameargsT)r   Threaddaemonstart)r   r   	thread_notr   r   r   start_new_thread:   s      z'ThreadedTaskDispatcher.start_new_threadc              	   C   s   | j  | js@| jdkr@|  jd8  _| j  |  jd7  _q| jdkr|  jd8  _|  jd8  _| j| | j	  W 5 Q R  q| j
 }W 5 Q R X z|  W q  tk
r   | jd| Y q X q d S )Nr   r   zException when servicing %r)r   r   
stop_countactive_countr   waitr   discardr   notifypopleftserviceBaseExceptionr   	exception)r   r$   taskr   r   r   handler_threadA   s     


z%ThreadedTaskDispatcher.handler_threadc              	   C   s   | j  | j}d}t|| j }||k rr||kr:|d }q(|| |d7 }| | j| |  jd7  _|d }q ||kr|  j|| 7  _| j	  W 5 Q R X d S )Nr   r   )
r   r   lenr'   addr&   r1   r(   r   
notify_all)r   countr   r$   Zrunningr   r   r   set_thread_countX   s    


z'ThreadedTaskDispatcher.set_thread_countc              	   C   sf   | j V | j| | j  t| j}t| j| j | j }||krX| j	
d||  W 5 Q R X d S )NzTask queue depth is %d)r   r   appendr   r+   r2   r   r'   r(   r   warning)r   r0   Z
queue_sizeZidle_threadsr   r   r   add_taskk   s    

 zThreadedTaskDispatcher.add_taskT   c              	   C   s   |  d | j}t | }| j |rVt |krH| jdt| qV| jd q$|r| j	}t|dkr~| jdt| |r|
 }|  q~| j  W 5 Q R  dS W 5 Q R X dS )Nr   z%d thread(s) still runningg?zCanceling %d pending task(s)TF)r6   r   timer   r   r8   r2   r   r)   r   r,   cancelr   r4   )r   Zcancel_pendingtimeoutr   Z
expirationr   r0   r   r   r   shutdownv   s&    


zThreadedTaskDispatcher.shutdownN)Tr:   )__name__
__module____qualname____doc__r'   r(   r   r   r   r&   r1   r6   r9   r>   r   r   r   r   r   +   s   r   c                   @   s|   e Zd ZdZdZdZdZdZdZdZ	dZ
dZdZeZdd Zdd Zed	d
 Zdd Zdd Zdd Zdd Zdd ZdS )TaskFz200 OKr   Nc                 C   s.   || _ || _g | _|j}|dkr$d}|| _d S )N)1.01.1rD   )channelrequestresponse_headersversion)r   rF   rG   rI   r   r   r   r      s    zTask.__init__c                 C   sH   z|    |   |   W n& tk
rB   d| _| jjjr> Y nX d S )NT)r#   executefinishOSErrorclose_on_finishrF   adjZlog_socket_errorsr   r   r   r   r-      s    
zTask.servicec                 C   s&   | j dp"| j dp"| j d S )N1Z204Z304)status
startswithr   r   r   r   has_body   s
    

zTask.has_bodyc                    s  j }jjdd }g d }d }d }d  jD ]n\}}ddd |dD }|dkrljr4|}nq4|dkrx|}|dkr|}|d	kr|  	||f q4|d krԈj
d k	rԈjrtj
}	d|f  fd
d}|dkr|dkr|s|  n
	d n|  nP|dkrb|dkr4|  |sjjrR	d d_jsj|  ntdjjjj}	|s|	r	d|	f n	d|	pdf |s	dtjf _dj  dj }
dd tjdd dD }|
g| }dd| }|dS )NZ
CONNECTION -c                 S   s   g | ]}|  qS r   )
capitalize).0xr   r   r   
<listcomp>   s     z.Task.build_response_header.<locals>.<listcomp>zContent-LengthDateServer
Connectionc                      s    d kr d d_d S N)r[   closeT)r7   rM   r   Zconnection_close_headerrH   r   r   r   rM      s    
z3Task.build_response_header.<locals>.close_on_finishrD   r   )r[   z
Keep-AliverE   r]   )zTransfer-EncodingchunkedTzneither HTTP/1.0 or HTTP/1.1ZViaZwaitresszHTTP/ c                 S   s   g | ]}d | qS )z%s: %sr   )rV   Zhvr   r   r   rX     s    c                 S   s   | d S )Nr   r   )rW   r   r   r   <lambda>      z,Task.build_response_header.<locals>.<lambda>)keyz%s

z
latin-1)rI   rG   headersgetlowerrH   joinsplitrR   r7   content_lengthstrchunked_responserM   AssertionErrorrF   serverrN   identr   
start_timerP   sortedencode)r   rI   r
   Zcontent_length_headerZdate_headerZserver_headerZ
headernameZ	headervalrM   ro   
first_lineZ
next_lineslinesresr   r^   r   build_response_header   sx    






zTask.build_response_headerc                 C   s:   g }| j D ]$\}}| dkr q
|||f q
|| _ d S )Ncontent-length)rH   rg   r7   )r   rH   header_nameheader_valuer   r   r   remove_content_length_header  s    z!Task.remove_content_length_headerc                 C   s   t   | _d S r   )r;   rp   r   r   r   r   r#   #  s    z
Task.startc                 C   s&   | j s| d | jr"| jd d S )Nrb   s   0

)wrote_headerwriterl   rF   
write_soonr   r   r   r   rK   &  s    
zTask.finishc                 C   s  | j std| j}| js2|  }|| d| _|r| jr|}| j}| jr|t	t
|dd   dd }||d 7 }nP|d k	r|d || j  }|  jt
|7  _||kr| js| jd|  d| _|r|| n8|r|  jt
|7  _| js| jd| j  d| _d S )Nz1start_response was not called before body writtenT   rd   s   
z`application-written content exceeded the number of bytes specified by Content-Length header (%s)zfapplication-written content was ignored due to HTTP response that may not contain a message-body: (%s))completeRuntimeErrorrF   r{   rv   r}   rR   rj   rl   hexr2   upperrr   content_bytes_writtenlogged_write_excessr   r8   logged_write_no_bodyrP   )r   datarF   ZrhZtowriteclr   r   r   r|   -  sD    

"z
Task.write)r?   r@   rA   rM   rP   r{   rp   rj   r   r   r   r   rl   r   r   r-   propertyrR   rv   rz   r#   rK   r|   r   r   r   r   rC      s(   


b
rC   c                   @   s   e Zd ZdZdZdd ZdS )	ErrorTaskz(An error task produces an error responseTc                 C   sR   | j j}| \}}}|| _| j| | jd d| _t|| _	| 
| d S r\   )rG   errorZto_responserP   rH   extendr7   rM   r2   rj   r|   )r   erP   re   bodyr   r   r   rJ   [  s    
zErrorTask.executeN)r?   r@   rA   rB   r   rJ   r   r   r   r   r   V  s   r   c                   @   s$   e Zd ZdZdZdd Zdd ZdS )WSGITaskz8A WSGI task produces a response from a WSGI application.Nc           
   	      sP     }d fdd	} jj||}d}z|jtkr j}|	|}|r||krj|d k	rd 
  | _ d  j| d}W d S d }|D ]P}|d krt|} jd krd }	t|drt|}	|	dkr| _|r | q j}|d k	r, j|kr,d _ jjd	kr, jd
 j|f  W 5 |rJt|drJ|  X d S )Nc                    s8   j r|std|r8z jr(|d ng  _W 5 d }X d _ | jtk	rTtd|  d| ksdd| krltd|  _|D ]\}}|jtk	rtd|d	||f|jtk	rtd
|d	||fd|ksd|krtdd|ksd|krtd| }|dkrt	| _
qv|tkrvtd| qv j|  jS )Nz?start_response called a second time without providing exc_info.r   Tzstatus %s is not a string
z5carriage return/line feed character present in statuszHeader name z is not a string in zHeader value z;carriage return/line feed character present in header valuez:carriage return/line feed character present in header namerw   zS%s is a "hop-by-hop" header; it cannot be used by a WSGI application (see PEP 3333))r   rm   r{   rH   	__class__rk   
ValueErrorrP   rg   intrj   
hop_by_hopr   r|   )rP   re   exc_infokvklr   r   r   start_responseq  s\    






z(WSGITask.execute.<locals>.start_responseTr]   rb   F__len__r   HEADzVapplication returned too few bytes (%s) for specified Content-Length (%s) via app_iter)N)get_environmentrF   rn   Zapplicationhasattrr]   r   r   rj   preparerz   r|   r}   r2   r   rM   rG   commandr   r8   )
r   environr   Zapp_iterZcan_close_app_iterr   sizeZfirst_chunk_lenchunkZapp_iter_lenr   r   r   rJ   n  sR    A





zWSGITask.executec                 C   sL  | j }|dk	r|S | j}|j}| j}|j}|jj}|drJd|d }|r~||kr\d}n"|d }||r~|t	|d }|j
d |j
d t|j
d |j t|j|j|jjd| j |||j|j|jdtjdd	d	| tdd
}t|j D ]>\}}	|	 }	t|d}
|
dkr$d| }
|
|kr|	||
< q| jj|d< || _ |S )zReturns a WSGI environment.N/rS   r   r   zHTTP/%s)r   r   TF)ZREMOTE_ADDRZREMOTE_HOSTZREMOTE_PORTREQUEST_METHODZSERVER_PORTZSERVER_NAMESERVER_SOFTWAREZSERVER_PROTOCOLZSCRIPT_NAMEZ	PATH_INFOZREQUEST_URIQUERY_STRINGzwsgi.url_schemezwsgi.versionzwsgi.errorszwsgi.multithreadzwsgi.multiprocesszwsgi.run_oncez
wsgi.inputzwsgi.file_wrapperzwsgi.input_terminatedZHTTP_zwaitress.client_disconnected) r   rG   pathrF   rn   rN   
url_prefixrQ   lstripr2   addrrk   r   r   Zeffective_portZserver_namero   rI   request_uriqueryZ
url_schemesysstderrZget_body_streamr   dictre   itemsstriprename_headersrf   Zcheck_client_disconnected)r   r   rG   r   rF   rn   r   Zurl_prefix_with_trailing_slashrc   valueZmykeyr   r   r   r     s`    



zWSGITask.get_environment)r?   r@   rA   rB   r   rJ   r   r   r   r   r   r   i  s   }r   )collectionsr   socketr   r   r;   buffersr   Z	utilitiesr   r   r   r   	frozensetr   r   rC   r   r   r   r   r   r   <module>   s"   c I