
    AҐi$                     b    d Z ddlmZmZ ddlmZ ddlmZ  G d de      Z G d d	      Z	d	dgZ
y
)zd
HTTP/2 stream state management.

Each HTTP/2 stream represents a single request/response exchange.
    )Enumauto)BytesIO   )HTTP2StreamErrorc                   r    e Zd ZdZ e       Z e       Z e       Z e       Z e       Z	 e       Z
 e       Zy)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     N/var/www/descvideos/venv/lib/python3.12/site-packages/gunicorn/http2/stream.pyr	   r	      s8    B6DVNfO6DVFr   r	   c                       e Zd ZdZd Zed        Zed        Zed        Zed        Z	ddZ
ddZd	 Zdd
ZddZd ZddZd ZddZd Zd Zd Zd Zd Zd Zy)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                    || _         || _        t        j                  | _        g | _        t               | _        d| _        d| _	        d| _
        d| _        |j                  | _        d| _        d| _        d| _        d| _        d| _        y)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)selfr   r   s      r   __init__zHTTP2Stream.__init__%   s     #$ !%%
  "#I % !&%*"!& &99  "&  "#$ "'r   c                 &    | j                   dz  dk(  S )z;Check if this is a client-initiated stream (odd stream ID).   r   r   r,   s    r   is_client_streamzHTTP2Stream.is_client_streamJ        ~~!Q&&r   c                 &    | j                   dz  dk(  S )z<Check if this is a server-initiated stream (even stream ID).r/   r   r0   r1   s    r   is_server_streamzHTTP2Stream.is_server_streamO   r3   r   c                 Z    | j                   t        j                  t        j                  fv S )z&Check if this stream can receive data.)r   r	   r   r   r1   s    r   can_receivezHTTP2Stream.can_receiveT   s,     zz))
 
 	
r   c                 Z    | j                   t        j                  t        j                  fv S )z#Check if this stream can send data.)r   r	   r   r   r1   s    r   can_sendzHTTP2Stream.can_send\   s,     zz**
 
 	
r   c                    | j                   t        j                  k(  rt        j                  | _         nY| j                   t        j                  t        j                  fvr-t        | j                  d| j                   j                         | j                  j                  |       |r| j                          d| _        yy)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_streams      r   receive_headerszHTTP2Stream.receive_headersd   s     ::)))$))DJZZ 0 0+2O2OPP"24::??2CD 
 	##G,##%$(D! r   c                     | j                   s-t        | j                  d| j                  j                         | j
                  j                  |       |r| j                          d| _        yy)zProcess received DATA frame.

        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)	r7   r   r   r   r;   r    writer=   r!   r,   datar@   s      r   receive_datazHTTP2Stream.receive_data|   sf     "/

/@A 
 	%##%$(D! r   c                     | j                   s-t        | j                  d| j                  j                         || _        | j                          d| _        y)zmProcess received trailing headers.

        Args:
            trailers: List of (name, value) tuples
        z!Cannot receive trailers in state TN)r7   r   r   r   r;   r'   r=   r!   r,   r'   s     r   receive_trailerszHTTP2Stream.receive_trailers   sQ     "3DJJOO3DE 
 !! $r   c                     | j                   s-t        | j                  d| j                  j                         d| _        d| _        |r| j                          d| _        yy)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)	r9   r   r   r   r;   r"   r#   _half_close_localr$   r>   s      r   send_headerszHTTP2Stream.send_headers   s`     }}"/

/@A 
 !%%)"""$%)D" r   c                     | j                   s-t        | j                  d| j                  j                         |r| j                          d| _        yy)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)r9   r   r   r   r;   rK   r$   rD   s      r   	send_datazHTTP2Stream.send_data   sP     }}",TZZ__,=> 
 ""$%)D" r   c                     | j                   s-t        | j                  d| j                  j                         || _        | j                          d| _        y)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)r9   r   r   r   r;   r(   rK   r$   rH   s     r   send_trailerszHTTP2Stream.send_trailers   sP     }}"00AB  "* !%r   c                 J    t         j                  | _        d| _        d| _        y)zvReset this stream with RST_STREAM.

        Args:
            error_code: HTTP/2 error code (default: CANCEL)
        TNr	   r   r   r$   r!   )r,   
error_codes     r   resetzHTTP2Stream.reset   s!     !''
!% $r   c                 J    t         j                  | _        d| _        d| _        y)zClose this stream normally.TNrR   r1   s    r   closezHTTP2Stream.close   s     ''
!% $r   Nc                 d    |t        dt        d|            | _        ||| _        ||| _        yy)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	exclusives       r   update_priorityzHTTP2Stream.update_priority   sA     #&q#c6*:#;D !'1D$ &/D# !r   c                 (   | j                   t        j                  k(  rt        j                  | _         y| j                   t        j                  k(  rt        j
                  | _         y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   r;   r1   s    r   rK   zHTTP2Stream._half_close_local   sg    ::)))$66DJZZ;999$++DJ"3DJJOO3DE r   c                 (   | j                   t        j                  k(  rt        j                  | _         y| j                   t        j                  k(  rt        j
                  | _         yt        | j                  d| j                   j                         )z)Transition to half-closed (remote) state.z"Cannot half-close remote in state N)	r   r	   r   r   r   r   r   r   r;   r1   s    r   r=   zHTTP2Stream._half_close_remote
  sg    ::)))$77DJZZ;888$++DJ"4TZZ__4EF r   c                 6    | j                   j                         S )zbGet the complete request body.

        Returns:
            bytes: The request body data
        )r    getvaluer1   s    r   get_request_bodyzHTTP2Stream.get_request_body  s       ))++r   c                 `    i }| j                   D ]  \  }}|j                  d      s|||<    |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,   pseudor;   values       r   get_pseudo_headerszHTTP2Stream.get_pseudo_headers  s>     // 	%KD%s#$t	% r   c                 r    | j                   D cg c]  \  }}|j                  d      s||f c}}S c c}}w )zGet regular (non-pseudo) headers from request.

        Returns:
            list: List of (name, value) tuples for regular headers
        re   rf   )r,   r;   ri   s      r   get_regular_headerszHTTP2Stream.get_regular_headers+  s>      $33
e??3' 5M
 	
 
s   3c           	          d| j                    d| j                  j                   d| j                   d| j                   d	S )Nz<HTTP2Stream id=z state=z req_complete=z resp_complete=>)r   r   r;   r!   r$   r1   s    r   __repr__zHTTP2Stream.__repr__7  sO    t~~. /ZZ__% & 112 3!334A7	
r   )F)   )NNN)r
   r   r   r   r-   propertyr2   r5   r7   r9   rA   rF   rI   rL   rN   rP   rT   rV   r^   rK   r=   rc   rj   rl   ro   r   r   r   r   r      s    #(J ' ' ' ' 
 
 
 
)0),% *.*(&$%%0

,


r   r   N)r   enumr   r   ior   errorsr   r	   r   __all__r   r   r   <module>rv      s:      $	$ 	_
 _
D	 -
(r   