U
    h<J                     @   s   d dl Z d dlZd dlZd dlZd dlmZmZ d dlmZ d dl	m
Z
mZ d dlmZ ddlmZ G dd	 d	eZG d
d dejZdS )    N)OverflowableBufferReadOnlyFileBasedBuffer)HTTPRequestParser)	ErrorTaskWSGITask)InternalServerError   )	wasyncorec                   @   s   e Zd ZdZdS )ClientDisconnectedz3Raised when attempting to write to a closed socket.N)__name__
__module____qualname____doc__ r   r   B/var/www/html/venv/lib/python3.8/site-packages/waitress/channel.pyr
      s   r
   c                   @   s   e Zd ZdZeZeZeZ	dZ
dZdZdZdZdZdZd*ddZdd Zd	d
 Zdd Zd+ddZdd Zdd Zdd Zdd Zd,ddZd-ddZdd Zd.ddZd/d d!Zd"d# Zd$d% Z d&d' Z!d(d) Z"dS )0HTTPChannelz
    Setting self.requests = [somerequest] prevents more requests from being
    received until the out buffers have been flushed.

    Setting self.requests = [] allows more requests to be received.
    Nr   Fc                 C   sr   || _ || _t|jg| _t  | _| _|t	j
t	j| _t | _t | _tjj| ||d || _g | _d S )N)map)serveradjr   outbuf_overflowoutbufstimeZcreation_timelast_activity
getsockoptsocket
SOL_SOCKET	SO_SNDBUFsendbuf_len	threadingLockrequests_lock	Conditionoutbuf_lockr	   
dispatcher__init__addrrequests)selfr   sockr%   r   r   r   r   r   r$   8   s    

zHTTPChannel.__init__c                 C   s   | j  S )z
        This method is inserted into the environment of any created task so it
        may occasionally check if the client has disconnected and interrupt
        execution.
        )	connectedr'   r   r   r   check_client_disconnectedK   s    z%HTTPChannel.check_client_disconnectedc                 C   s   | j p| jp| jS N)total_outbufs_len
will_closeclose_when_flushedr*   r   r   r   writableT   s    zHTTPChannel.writablec                 C   sf   | j s
d S | js| j}n| j| jjkr.| j}nd }| | | jrT| jsTd| _d| _	| j	rb| 
  d S )NFT)r)   r&   _flush_somer-   r   
send_bytes_flush_some_if_lockable_flush_exceptionr/   r.   handle_close)r'   flushr   r   r   handle_write[   s    
zHTTPChannel.handle_writeTc                 C   sp   |rlz||ddfW S  t k
rD   | jjr8| jd d| _Y dS  tk
rj   | jd d| _Y dS X d S )Ndo_closeFSocket errorT)FTz"Unexpected exception when flushing)OSErrorr   log_socket_errorslogger	exceptionr.   	Exception)r'   r6   r9   r   r   r   r4      s    zHTTPChannel._flush_exceptionc                 C   s&   | j p"| jp"t| j| jjkp"| j S r,   )r.   r/   lenr&   r   Zchannel_request_lookaheadr-   r*   r   r   r   readable   s    
zHTTPChannel.readablec                 C   sj   z|  | jj}W n2 tk
rD   | jjr6| jd |   Y d S X |r`t | _	| 
| nd| _d S )Nr:   F)recvr   Z
recv_bytesr;   r<   r=   r>   r5   r   r   receivedr)   )r'   datar   r   r   handle_read   s    
zHTTPChannel.handle_readc              	   C   sl   d| j _d}t|}| j@ | jd | |  j|7  _|  j|7  _d| _| 	  W 5 Q R X d| j _
dS )a  
        Send a 100-Continue header to the client. This is either called from
        receive (if no requests are running and the client expects it) or at
        the end of service (if no more requests are queued and a request has
        been read partially that expects it).
        Fs   HTTP/1.1 100 Continue

TN)requestexpect_continuer@   r"   r   appendcurrent_outbuf_countr-   sent_continuer1   	completed)r'   Zoutbuf_payload	num_bytesr   r   r   send_continue   s    zHTTPChannel.send_continuec              	   C   s   |sdS | j  |r| jdkr,| | j| _| j|}| jjr\| jjr\| js\| js\| 	  | jj
rd| _| jjs| j| j t| jdkr| j|  d| _|t|krq||d }qW 5 Q R X dS )zh
        Receives input asynchronously and assigns one or more requests to the
        channel.
        FNr   T)r    rG   parser_classr   rC   rH   headers_finishedr&   rK   rN   rL   emptyrI   r@   r   add_task)r'   rD   nr   r   r   rC      s6    
zHTTPChannel.receivedc                 C   sF   | j drBz(| j|d | j| jjk r2| j   W 5 | j   X d S NFr8   )r"   acquirereleaser1   r-   r   outbuf_high_watermarknotify)r'   r9   r   r   r   r3      s    z#HTTPChannel._flush_some_if_lockablec           	      C   s   d}d}| j d }| }|dkrt|| j}| j||d}|rl||d ||8 }||7 }|  j|8  _qd}qqt| j dkr| j d}z|	  W q t
k
r   | jd Y qX nd}|rqq|rt | _dS dS )Nr   Fr8   Tr   z'Unexpected error when closing an outbuf)r   __len__getr   sendskipr-   r@   popcloser?   r=   r>   r   r   )	r'   r9   sentZdobreakoutbufZ	outbuflenchunkZnum_sentZtocloser   r   r   r1      s6    

zHTTPChannel._flush_somec              
   C   sr   | j V | jD ]2}z|  W q tk
r>   | jd Y qX qd| _d| _| j   W 5 Q R X t	j
|  d S )Nz.Unknown exception while trying to close outbufr   F)r"   r   r^   r?   r=   r>   r-   r)   rX   r	   r#   )r'   r`   r   r   r   r5   1  s    
zHTTPChannel.handle_closec                 C   s    t j| | | | jj| j< dS )zTSee wasyncore.dispatcher

        This hook keeps track of opened channels.
        N)r	   r#   add_channelr   active_channels_fileno)r'   r   r   r   r   rb   ?  s    zHTTPChannel.add_channelc                 C   s.   | j }tj| | | jj}||kr*||= dS )zTSee wasyncore.dispatcher

        This hook keeps track of closed channels.
        N)rd   r	   r#   del_channelr   rc   )r'   r   fdacr   r   r   re   G  s
    zHTTPChannel.del_channelc              	   C   s  | j s
t|r| j |   | j s*tt|}|jtkrh| j| t	| j
j}| j| d| _nJ| j| j
jkrt	| j
j}| j| d| _| jd | |  j|7  _|  j|7  _| j| j
jkr| j| jdd\}}|s|r| j| j
jkr| j  W 5 Q R X |S dS )Nr   rF   Fr8   )r)   r
   r"   #_flush_outbufs_below_high_watermarkr@   	__class__r   r   rI   r   r   r   rJ   rW   r-   r2   r4   r1   r   pull_trigger)r'   rD   rM   Znextbufflushedr>   r   r   r   
write_soonW  sD    
 
zHTTPChannel.write_soonc              	   C   s   | j | jjkr| jj | j| jdd\}}|rP| j  | j  W 5 Q R  d S | j	rz| j | jjkrz| j  | j  qPW 5 Q R X d S rT   )
r-   r   rW   r"   r4   r1   r   rj   waitr)   )r'   _r>   r   r   r   rh     s    


z/HTTPChannel._flush_outbufs_below_high_watermarkc                 C   sT  | j d }|jr| | |}n| | |}z| jr<|  nd|_W n tk
rt   | j	d|j
j  d|_Y n tk
rJ   | jd|j
j  |js@| jjrt }nd}|j}|j}| | j}t||_||_z|d |jd< W n tk
r   Y nX | | |}z|  W n tk
r<   d|_Y nX nd|_Y nX |jr| j( d| _| j D ]}|  qhg | _ W 5 Q R X nt| j dkr|   | jdkr| jj| _|  | jh | j d | jr| j r| j !|  n8| jr*| j
dk	r*| j
j"r*| j
j#r*| j$s*| %  W 5 Q R X | jrF| j &  t'' | _(dS )	z]Execute one request. If there are more, we add another task to the
        server at the end.r   Tz$Client disconnected while serving %szException while serving %sz:The server encountered an unexpected internal server errorZ
CONNECTIONr   N))r&   errorerror_task_class
task_classr)   serviceZclose_on_finishr
   r=   inforG   pathr?   r>   Zwrote_headerr   Zexpose_tracebacks	traceback
format_excversionheadersrO   r   KeyErrorr    r/   r^   r@   rh   rJ   rW   r]   r   rR   rH   rP   rK   rN   rj   r   r   )r'   rG   taskbodyZreq_versionZreq_headersZerr_requestr   r   r   rr     sz    









zHTTPChannel.servicec                 C   s    d| _ d| _t | _g | _dS )z%Cancels all pending / active requestsTFN)r.   r)   r   r   r&   r*   r   r   r   cancel  s    
zHTTPChannel.cancel)N)T)T)T)N)N)#r   r   r   r   r   rq   r   rp   r   rO   rG   r   r.   r/   rK   r-   rJ   r$   r+   r0   r7   r4   rA   rE   rN   rC   r3   r1   r5   rb   re   rl   rh   rr   r|   r   r   r   r   r      s:   
	&
/

1

1cr   )r   r   r   ru   Zwaitress.buffersr   r   Zwaitress.parserr   Zwaitress.taskr   r   Zwaitress.utilitiesr    r	   r?   r
   r#   r   r   r   r   r   <module>   s   