o
    i                     @   s4   d Z ddlmZ ddlmZmZ G dd deZdS )zAsync uWSGI protocol parser for ASGI workers.

Reuses the parsing logic from gunicorn/uwsgi/message.py, only async I/O differs.
    )UWSGIRequest)InvalidUWSGIHeaderUnsupportedModifierc                   @   sZ   e Zd ZdZdddZedddZdd Zd	d
 Zdd Z	dddZ
dd Zdd ZdS )AsyncUWSGIRequestaR  Async version of UWSGIRequest.

    Reuses all parsing logic from the sync version, only async I/O differs.
    The following methods are reused from the parent class:
    - _parse_vars() - pure parsing, no I/O
    - _extract_request_info() - pure transformation
    - _check_allowed_ip() - no I/O
    - should_close() - simple logic
       c                 C   s   || _ || _|| _|| _|| _d | _d | _d | _d | _d| _	d| _
g | _g | _d | _|jr/dnd| _d| _i | _d| _d| _d | _d| _d| _d| _d S )N )r   r   httpshttpFr   )cfgunreader	peer_addrremote_addr
req_numbermethoduripathqueryfragmentversionheaderstrailersbodyis_sslscheme
must_close
uwsgi_vars	modifier1	modifier2proxy_protocol_infocontent_lengthchunked_body_remaining)selfr
   r   r   r    r#   G/home/ubuntu/.local/lib/python3.10/site-packages/gunicorn/asgi/uwsgi.py__init__   s.   
zAsyncUWSGIRequest.__init__c                    s*   | ||||}|   | I dH  |S )a  Parse a uWSGI request asynchronously.

        Args:
            cfg: gunicorn config object
            unreader: AsyncUnreader instance
            peer_addr: client address tuple
            req_number: request number on this connection (for keepalive)

        Returns:
            AsyncUWSGIRequest: Parsed request object

        Raises:
            InvalidUWSGIHeader: If the uWSGI header is malformed
            UnsupportedModifier: If modifier1 is not 0
            ForbiddenUWSGIRequest: If source IP is not allowed
        N)_check_allowed_ip_async_parse)clsr
   r   r   r   reqr#   r#   r$   parse@   s
   zAsyncUWSGIRequest.parsec                    s   |  dI dH }t|dk rtd|d | _t|dd d}|d | _| jdkr1t| j|dkrL|  |I dH }t||k rGtd| | | 	  | 
  dS )	z=Async version of parse() - reads data then uses sync parsing.   Nzincomplete headerr   r      littlezincomplete vars block)_async_read_exactlenr   r   int
from_bytesr   r   _parse_vars_extract_request_info_set_body_reader)r"   headerdatasize	vars_datar#   r#   r$   r'   W   s    




zAsyncUWSGIRequest._async_parsec                    sZ   t  }t||k r)| j|t| I dH }|s	 t|S || t||k s
t|S )z'Read exactly size bytes asynchronously.N)	bytearrayr/   r   readextendbytes)r"   sizebufchunkr#   r#   r$   r.   o   s   
z#AsyncUWSGIRequest._async_read_exactc                 C   sN   d}d| j v rztt| j d d}W n ty   d}Y nw || _|| _dS )z$Set up body state for async reading.r   CONTENT_LENGTHN)r   maxr0   
ValueErrorr   r!   )r"   r   r#   r#   r$   r4   y   s   

z"AsyncUWSGIRequest._set_body_reader    c                    sH   | j dkrdS t|| j }| j|I dH }|r"|  j t|8  _ |S )zRead body chunk asynchronously.

        Args:
            size: Maximum bytes to read

        Returns:
            bytes: Body data, empty bytes when body is exhausted
        r       N)r!   minr   r9   r/   )r"   r<   to_readdatar#   r#   r$   	read_body   s   
	zAsyncUWSGIRequest.read_bodyc                    s6   | j dkr| dI dH }|sdS | j dksdS dS )zcDrain unread body data.

        Should be called before reusing connection for keepalive.
        r   rB   N)r!   rG   )r"   rF   r#   r#   r$   
drain_body   s   
zAsyncUWSGIRequest.drain_bodyc                 C   s,   |  }| jD ]\}}||kr|  S qdS )zGet header by name (case-insensitive).

        Args:
            name: Header name to look up

        Returns:
            Header value if found, None otherwise
        N)upperr   )r"   namehvr#   r#   r$   
get_header   s   	zAsyncUWSGIRequest.get_headerN)r   )rB   )__name__
__module____qualname____doc__r%   classmethodr*   r'   r.   r4   rG   rH   rM   r#   r#   r#   r$   r      s    
#


r   N)rQ   gunicorn.uwsgi.messager   gunicorn.uwsgi.errorsr   r   r   r#   r#   r#   r$   <module>   s   