o
    iP                     @   st   d Z ddlZddlmZmZmZmZmZ ddlm	Z	 ddl
mZ dadadadadadd ZG d	d
 d
Zd
gZdS )z
Async HTTP/2 server connection implementation for ASGI workers.

Uses the hyper-h2 library for HTTP/2 protocol handling with
asyncio for non-blocking I/O.
    N   )
HTTP2ErrorHTTP2ProtocolErrorHTTP2ConnectionErrorHTTP2NotAvailableHTTP2ErrorCode)HTTP2Stream)HTTP2Requestc                   C   sd   t durdS z!ddlma  ddlma ddlma ddl	m
a ddlma W dS  ty1   t w )z$Lazily import h2 library components.Nr   )_h2h2.connection
connection	h2.configconfig
_h2_config	h2.eventsevents
_h2_eventsh2.exceptions
exceptions_h2_exceptionsh2.settingssettings_h2_settingsImportErrorr    r   r   S/home/ubuntu/.local/lib/python3.10/site-packages/gunicorn/http2/async_connection.py
_import_h2   s   r   c                   @   s   e Zd ZdZdZdd Zdd Zd5dd	Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zd5ddZdd Zd6d!d"Zd#d$ Zd5d%d&Zd7d(d)Zd8d+d,Zd-d. Zed/d0 Zd1d2 Zd3d4 ZdS )9AsyncHTTP2ConnectionzAsync HTTP/2 server-side connection handler for ASGI.

    Manages the HTTP/2 connection state and multiplexed streams
    using asyncio for non-blocking I/O operations.
    i   c                 C   s   t   || _|| _|| _|| _i | _t | _|j	| _
|j| _|j| _|j| _tjddd}tj|d| _d| _d| _d| _dS )aP  Initialize an async HTTP/2 server connection.

        Args:
            cfg: Gunicorn configuration object
            reader: asyncio StreamReader
            writer: asyncio StreamWriter
            client_addr: Client address tuple (host, port)

        Raises:
            HTTP2NotAvailable: If h2 library is not installed
        Fzutf-8)client_sideheader_encoding)r   N)r   cfgreaderwriterclient_addrstreamsasyncioQueue_request_queuehttp2_initial_window_sizeinitial_window_sizehttp2_max_concurrent_streamsmax_concurrent_streamshttp2_max_frame_sizemax_frame_sizehttp2_max_header_list_sizemax_header_list_sizer   H2Configurationr
   H2Connectionh2_conn_closed_initialized_receive_task)selfr    r!   r"   r#   r   r   r   r   __init__:   s&   

zAsyncHTTP2Connection.__init__c              
      sb   | j rdS | jtjj| jtjj| jtjj	| j
tjj| ji | j  |  I dH  d| _ dS )zSend initial HTTP/2 settings to client.

        Should be called after the SSL handshake completes and
        before processing any data.
        NT)r4   r2   update_settingsr   SettingCodesMAX_CONCURRENT_STREAMSr+   INITIAL_WINDOW_SIZEr)   MAX_FRAME_SIZEr-   MAX_HEADER_LIST_SIZEr/   initiate_connection_send_pending_datar6   r   r   r   r>   e   s   





z(AsyncHTTP2Connection.initiate_connectionNc           	   
      s  z |durt j| j| j|dI dH }n
| j| jI dH }W n ttfy6 } ztd| d}~ww |s>d| _g S z| j	
|}W n tjyc } z| jtjdI dH  tt|d}~w tjy } z| jtjdI dH  tt|d}~w tjy } z$t|dd}|dur| j|dI dH  n
| jtjdI dH  tt|d}~w tjy } z| jtjdI dH  tt|d}~w tjy } z| jtjdI dH  tt|d}~ww g }|D ]}| |}|dur|| q|  I dH  |S )ah  Receive data and return completed requests.

        Args:
            timeout: Optional timeout in seconds for read operation

        Returns:
            list: List of HTTP2Request objects for completed requests

        Raises:
            HTTP2ConnectionError: On protocol or connection errors
            asyncio.TimeoutError: If timeout expires
        NtimeoutzSocket read error: T
error_coderD   )r%   wait_forr!   readREAD_BUFFER_SIZEOSErrorIOErrorr   r3   r2   receive_datar   FlowControlErrorcloser   FLOW_CONTROL_ERRORr   strFrameTooLargeErrorFRAME_SIZE_ERRORInvalidSettingsValueErrorgetattrPROTOCOL_ERRORTooManyStreamsErrorREFUSED_STREAMProtocolError_handle_eventappendr?   )	r6   rB   dataer   rD   completed_requestseventrequestr   r   r   rJ   z   sd   

z!AsyncHTTP2Connection.receive_datac                 C   s   t |tjr| |S t |tjr| |S t |tjr!| |S t |tjr.| 	| dS t |tj
r7	 dS t |tjrD| | dS t |tjrM	 dS t |tjrZ| | dS t |tjre| |S dS )zHandle a single h2 event.

        Args:
            event: h2 event object

        Returns:
            HTTP2Request if a request is complete, None otherwise
        N)
isinstancer   RequestReceived_handle_request_receivedDataReceived_handle_data_receivedStreamEnded_handle_stream_endedStreamReset_handle_stream_resetWindowUpdatedPriorityUpdated_handle_priority_updatedSettingsAcknowledgedConnectionTerminated_handle_connection_terminatedTrailersReceived_handle_trailers_receivedr6   r\   r   r   r   rW      s0   	






z"AsyncHTTP2Connection._handle_eventc                 C   s2   |j }|j}t|| }|| j|< |j|dd dS )z-Handle RequestReceived event (HEADERS frame).F
end_streamN)	stream_idheadersr   r$   receive_headers)r6   r\   rr   rs   streamr   r   r   r`      s
   

z-AsyncHTTP2Connection._handle_request_receivedc                 C   s   |j }|j}| j|}|du rdS |j|dd t|dkr\z| jjt||d | jjt|dd W dS  tt	j
fy[   d| _z| jjtjd W Y dS  tyZ   Y Y dS w w dS )zHandle DataReceived event.NFrp   r   )rr   TrC   )rr   rY   r$   getrJ   lenr2   increment_flow_control_window
ValueErrorr   rK   r3   close_connectionr   rM   	Exception)r6   r\   rr   rY   ru   r   r   r   rb      s,   
	z*AsyncHTTP2Connection._handle_data_receivedc                 C   s4   |j }| j|}|du rdS d|_t|| j| jS )zHandle StreamEnded event.NT)rr   r$   rv   request_completer	   r    r#   r6   r\   rr   ru   r   r   r   rd     s   z)AsyncHTTP2Connection._handle_stream_endedc                 C   s.   |j }| j|}|dur||j dS dS )zHandle StreamReset event.N)rr   r$   rv   resetrD   r}   r   r   r   rf     s
   z)AsyncHTTP2Connection._handle_stream_resetc                 C   s
   d| _ dS )z"Handle ConnectionTerminated event.TNr3   ro   r   r   r   rl   $  s   
z2AsyncHTTP2Connection._handle_connection_terminatedc                 C   s:   |j }| j|}|du rdS ||j t|| j| jS )zHandle TrailersReceived event.N)rr   r$   rv   receive_trailersrs   r	   r    r#   r}   r   r   r   rn   (  s   z.AsyncHTTP2Connection._handle_trailers_receivedc                 C   s4   | j |j}|dur|j|j|j|jd dS dS )zHandle PriorityUpdated event (PRIORITY frame).

        Args:
            event: PriorityUpdated event with priority info
        N)weight
depends_on	exclusive)r$   rv   rr   update_priorityr   r   r   )r6   r\   ru   r   r   r   ri   3  s   
z-AsyncHTTP2Connection._handle_priority_updatedc                    s   |dk s	|dkrt d| | j|}|du r"t d| ddt|fg}|D ]\}}|| t|f q+| jj||dd	 |  I dH  dS )
a  Send an informational response (1xx) on a stream.

        This is used for 103 Early Hints and other 1xx responses.
        Informational responses are sent before the final response
        and do not end the stream.

        Args:
            stream_id: The stream ID
            status: HTTP status code (100-199)
            headers: List of (name, value) header tuples

        Raises:
            HTTP2Error: If status is not in 1xx range
        d      zInvalid informational status: NzStream z
 not found:statusFrp   )	r   r$   rv   rN   rX   lowerr2   send_headersr?   )r6   rr   statusrs   ru   response_headersnamevaluer   r   r   send_informationalA  s   z'AsyncHTTP2Connection.send_informationalc           
         s   | j |}|du rdS dt|fg}|D ]\}}|| t|f q|du p/t|dk}	z-| jj|||	d |j||	d |  I dH  |r[t|dkr[| j	||ddI dH  W dS  t
jyq   |  | | Y dS w )aX  Send a response on a stream.

        Args:
            stream_id: The stream ID to respond on
            status: HTTP status code (int)
            headers: List of (name, value) header tuples
            body: Optional response body bytes

        Returns:
            bool: True if response sent, False if stream was already closed
        NFr   r   rp   T)r$   rv   rN   rX   r   rw   r2   r   r?   	send_datar   StreamClosedErrorrL   cleanup_stream)
r6   rr   r   rs   bodyru   r   r   r   rq   r   r   r   send_responsea  s(   
z"AsyncHTTP2Connection.send_responsec              	      s   d}t |D ]q}| j|}|dkr|  S zLtj| j| jddI dH }|r[| j|}|D ]!}t	|t
jrD|j|krC W  dS q1t	|t
jrRd| _ W  dS q1|  I dH  nd| _W  dS W q tjym   Y q tjyx   Y  dS w | j|S )zWait for flow control window to become positive.

        Returns:
            int: Available window size, or -1 if waiting failed
        2   r   g?rA   NT)ranger2   local_flow_control_windowr%   rE   r!   rF   rG   rJ   r^   r   re   rr   rk   r3   r?   TimeoutErrorr   rV   )r6   rr   max_wait_attempts_	availableincomingr   r\   r   r   r   _wait_for_flow_control_window  s@   


z2AsyncHTTP2Connection._wait_for_flow_control_windowFc           
   	      s  | j |}|du rdS |}zd|rj| j|}t|| jt|}|dkrD|  I dH  | |I dH }|dkr;W dS t|| jt|}|d| }||d }|oWt|dk}	| jj	|||	d |  I dH  |s|j	||d W dS  t
jt
jfy   |  | | Y dS w )a  Send data on a stream.

        Args:
            stream_id: The stream ID
            data: Body data bytes
            end_stream: Whether this ends the stream

        Returns:
            bool: True if data sent, False if stream was already closed
        NFr   rp   T)r$   rv   r2   r   minr-   rw   r?   r   r   r   r   rK   rL   r   )
r6   rr   rY   rq   ru   data_to_sendr   
chunk_sizechunkis_finalr   r   r   r     s8   
zAsyncHTTP2Connection.send_datac                    s   | j |}|du rdS |jsdS g }|D ]\}}| }|dr+td| d||t|f qz| jj	||dd |
| |  I dH  W dS  tjya   |  | | Y dS w )a  Send trailing headers on a stream.

        Trailers are headers sent after the response body, commonly used
        for gRPC status codes, checksums, and timing information.

        Args:
            stream_id: The stream ID
            trailers: List of (name, value) trailer tuples

        Raises:
            HTTP2Error: If stream not found, headers not sent, or pseudo-headers used

        Returns:
            bool: True if trailers sent, False if stream was already closed
        NF:zPseudo-header 'z' not allowed in trailersTrp   )r$   rv   response_headers_sentr   
startswithr   rX   rN   r2   r   send_trailersr?   r   r   rL   r   )r6   rr   trailersru   trailer_headersr   r   lnamer   r   r   r     s,   


z"AsyncHTTP2Connection.send_trailersc                    sL   |r|  nd}dtt|fg}|r|d | ||||I dH  dS )z#Send an error response on a stream.    zcontent-length)zcontent-typeztext/plain; charset=utf-8N)encoderN   rw   rX   r   )r6   rr   status_codemessager   rs   r   r   r   
send_error  s   
zAsyncHTTP2Connection.send_error   c                    sB   | j |}|dur|| | jj||d |  I dH  dS )zReset a stream with RST_STREAM.NrC   )r$   rv   r~   r2   reset_streamr?   )r6   rr   rD   ru   r   r   r   r     s   
z!AsyncHTTP2Connection.reset_streamr   c                    s   | j rdS d| _ |du r| jrt| j nd}z| jj|d |  I dH  W n	 ty2   Y nw z| j	  | j
 I dH  W dS  tyM   Y dS w )z,Close the connection gracefully with GOAWAY.NTr   rC   )r3   r$   maxkeysr2   rz   r?   r{   r"   rL   wait_closed)r6   rD   last_stream_idr   r   r   rL     s$   
zAsyncHTTP2Connection.closec              
      sh   | j  }|r2z| j| | j I dH  W dS  ttfy1 } z
d| _td| d}~ww dS )z,Send any pending data from h2 to the socket.NTzSocket write error: )	r2   r   r"   writedrainrH   rI   r3   r   )r6   rY   rZ   r   r   r   r?   0  s   
z'AsyncHTTP2Connection._send_pending_datac                 C   s   | j S )zCheck if connection is closed.r   r@   r   r   r   	is_closed;  s   zAsyncHTTP2Connection.is_closedc                 C   s   | j |d dS )z-Remove a stream after processing is complete.N)r$   pop)r6   rr   r   r   r   r   @  s   z#AsyncHTTP2Connection.cleanup_streamc                 C   s   dt | j d| j dS )Nz<AsyncHTTP2Connection streams=z closed=>)rw   r$   r3   r@   r   r   r   __repr__D  s   zAsyncHTTP2Connection.__repr__)N)F)r   )r   N)__name__
__module____qualname____doc__rG   r7   r>   rJ   rW   r`   rb   rd   rf   rl   rn   ri   r   r   r   r   r   r   r   rL   r?   propertyr   r   r   r   r   r   r   r   0   s6    +
H&
 (
(+
,
	
	
r   )r   r%   errorsr   r   r   r   r   ru   r   r]   r	   r
   r   r   r   r   r   r   __all__r   r   r   r   <module>   s"       
 