o
    j*                     @   sV   d 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	Z	d	dgZ
d
S )zd
HTTP/2 stream state management.

Each HTTP/2 stream represents a single request/response exchange.
    )Enumauto)BytesIO   )HTTP2StreamErrorc                   @   s:   e Zd ZdZe Ze Ze Ze Ze Z	e Z
e ZdS )StreamStatez8HTTP/2 stream states as defined in RFC 7540 Section 5.1.N)__name__
__module____qualname____doc__r   IDLERESERVED_LOCALRESERVED_REMOTEOPENHALF_CLOSED_LOCALHALF_CLOSED_REMOTECLOSED r   r   J/var/www/ai-app/venv/lib/python3.10/site-packages/gunicorn/http2/stream.pyr      s    
r   c                   @   s   e Zd ZdZdd Zedd Zedd Zedd	 Ze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d0ddZdd Zd1dd Zd!d" Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zd-d. ZdS )2HTTP2StreamzRepresents a single HTTP/2 stream.

    Manages stream state, headers, and body data for a single
    request/response exchange within an HTTP/2 connection.
    c                 C   sv   || _ || _tj| _g | _t | _d| _d| _	d| _
d| _|j| _d| _d| _d| _d| _d| _g | _d| _d| _dS )zInitialize an HTTP/2 stream.

        Args:
            stream_id: The unique stream identifier (odd for client-initiated)
            connection: The parent HTTP2ServerConnection
        FN   r   )	stream_id
connectionr   r   staterequest_headersr   request_bodyrequest_completeresponse_startedresponse_headers_sentresponse_completeinitial_window_sizewindow_sizetrailersresponse_trailerspriority_weightpriority_depends_onpriority_exclusive_body_chunks_body_event_body_complete)selfr   r   r   r   r   __init__%   s$   
zHTTP2Stream.__init__c                 C      | j d dkS )z;Check if this is a client-initiated stream (odd stream ID).   r   r   r*   r   r   r   is_client_streamO      zHTTP2Stream.is_client_streamc                 C   r,   )z<Check if this is a server-initiated stream (even stream ID).r-   r   r.   r/   r   r   r   is_server_streamT   r1   zHTTP2Stream.is_server_streamc                 C      | j tjtjfv S )z&Check if this stream can receive data.)r   r   r   r   r/   r   r   r   can_receiveY      zHTTP2Stream.can_receivec                 C   r3   )z#Check if this stream can send data.)r   r   r   r   r/   r   r   r   can_senda   r5   zHTTP2Stream.can_sendFc                 C   sd   | j tjkrtj| _ n| j tjtjfvrt| jd| j j | j	| |r0| 
  d| _dS dS )zProcess received HEADERS frame.

        Args:
            headers: List of (name, value) tuples
            end_stream: True if END_STREAM flag is set

        Raises:
            HTTP2StreamError: If headers received in invalid state
        z Cannot receive headers in state TN)r   r   r   r   r   r   r   namer   extend_half_close_remoter   r*   headers
end_streamr   r   r   receive_headersi   s   


zHTTP2Stream.receive_headersc                 C   s|   | j st| jd| jj |r| j| | jr| j  | j	
| |r:|   d| _d| _| jr<| j  dS dS dS )zProcess received DATA frame with streaming support.

        Args:
            data: Bytes received
            end_stream: True if END_STREAM flag is set

        Raises:
            HTTP2StreamError: If data received in invalid state
        zCannot receive data in state TN)r4   r   r   r   r7   r'   appendr(   setr   writer9   r   r)   r*   datar<   r   r   r   receive_data   s$   

zHTTP2Stream.receive_datac                 C   4   | j st| jd| jj || _|   d| _dS )zmProcess received trailing headers.

        Args:
            trailers: List of (name, value) tuples
        z!Cannot receive trailers in state TN)r4   r   r   r   r7   r"   r9   r   r*   r"   r   r   r   receive_trailers   s   
zHTTP2Stream.receive_trailersc                 C   sB   | j st| jd| jj d| _d| _|r|   d| _dS dS )zMark headers as sent.

        Args:
            headers: List of (name, value) tuples to send
            end_stream: True if this completes the response

        Raises:
            HTTP2StreamError: If headers cannot be sent in current state
        zCannot send headers in state TN)	r6   r   r   r   r7   r   r   _half_close_localr   r:   r   r   r   send_headers   s   

zHTTP2Stream.send_headersc                 C   s6   | j st| jd| jj |r|   d| _dS dS )zMark data as sent.

        Args:
            data: Bytes to send
            end_stream: True if this completes the response

        Raises:
            HTTP2StreamError: If data cannot be sent in current state
        zCannot send data in state TN)r6   r   r   r   r7   rG   r   rA   r   r   r   	send_data   s   

zHTTP2Stream.send_datac                 C   rD   )zMark trailers as sent and close the stream.

        Args:
            trailers: List of (name, value) trailer tuples

        Raises:
            HTTP2StreamError: If trailers cannot be sent in current state
        zCannot send trailers in state TN)r6   r   r   r   r7   r#   rG   r   rE   r   r   r   send_trailers   s   	
zHTTP2Stream.send_trailers   c                 C      t j| _d| _d| _dS )zvReset this stream with RST_STREAM.

        Args:
            error_code: HTTP/2 error code (default: CANCEL)
        TNr   r   r   r   r   )r*   
error_coder   r   r   reset   s   
zHTTP2Stream.resetc                 C   rL   )zClose this stream normally.TNrM   r/   r   r   r   close   s   
zHTTP2Stream.closeNc                 C   s>   |durt dtd|| _|dur|| _|dur|| _dS dS )a   Update stream priority from PRIORITY frame.

        Args:
            weight: Priority weight (1-256), higher = more resources
            depends_on: Stream ID this stream depends on
            exclusive: Whether this is an exclusive dependency
        Nr      )maxminr$   r%   r&   )r*   weight
depends_on	exclusiver   r   r   update_priority   s   
zHTTP2Stream.update_priorityc                 C   F   | j tjkrtj| _ dS | j tjkrtj| _ dS t| jd| j j )z(Transition to half-closed (local) state.z!Cannot half-close local in state N)	r   r   r   r   r   r   r   r   r7   r/   r   r   r   rG        zHTTP2Stream._half_close_localc                 C   rX   )z)Transition to half-closed (remote) state.z"Cannot half-close remote in state N)	r   r   r   r   r   r   r   r   r7   r/   r   r   r   r9     rY   zHTTP2Stream._half_close_remotec                 C   s
   | j  S )zbGet the complete request body.

        Returns:
            bytes: The request body data
        )r   getvaluer/   r   r   r   get_request_body%  s   
zHTTP2Stream.get_request_bodyc                    sn   ddl }| jdu r| | _| js| jr| j  	 | jr$| jdS | jr)dS | j  | j I dH  q)zRead next body chunk asynchronously for streaming.

        Returns:
            bytes: Next chunk of body data, or None if body is complete.
        r   N)	asyncior(   Eventr'   r)   r?   popclearwait)r*   r\   r   r   r   read_body_chunk-  s   



zHTTP2Stream.read_body_chunkc                 C   s*   i }| j D ]\}}|dr|||< q|S )zExtract HTTP/2 pseudo-headers from request headers.

        Returns:
            dict: Mapping of pseudo-header names to values
                  (e.g., {':method': 'GET', ':path': '/'})
        :)r   
startswith)r*   pseudor7   valuer   r   r   get_pseudo_headersJ  s   
zHTTP2Stream.get_pseudo_headersc                 C   s   dd | j D S )zGet regular (non-pseudo) headers from request.

        Returns:
            list: List of (name, value) tuples for regular headers
        c                 S   s"   g | ]\}}| d s||fqS )rb   )rc   ).0r7   re   r   r   r   
<listcomp>]  s    z3HTTP2Stream.get_regular_headers.<locals>.<listcomp>)r   r/   r   r   r   get_regular_headersW  s   zHTTP2Stream.get_regular_headersc              	   C   s(   d| j  d| jj d| j d| j d	S )Nz<HTTP2Stream id=z state=z req_complete=z resp_complete=>)r   r   r7   r   r   r/   r   r   r   __repr__c  s   
zHTTP2Stream.__repr__)F)rK   )NNN)r   r	   r
   r   r+   propertyr0   r2   r4   r6   r=   rC   rF   rH   rI   rJ   rO   rP   rW   rG   r9   r[   ra   rf   ri   rk   r   r   r   r   r      s6    *





 




r   N)r   enumr   r   ior   errorsr   r   r   __all__r   r   r   r   <module>   s     P