
    AҐi7                         d Z ddlZddlZddlmZ ddlmZ ddlmZ ddlm	Z	 ddl
mZ ddlmZ d	 Z G d
 d      Z G d dej                         Zy)z
ASGI protocol handler for gunicorn.

Implements asyncio.Protocol to handle HTTP/1.x and HTTP/2 connections
and dispatch to ASGI applications.
    N)datetime)AsyncUnreader)AsyncRequest)AsyncUWSGIRequest)
NoMoreData)UWSGIParseExceptionc                 &    | rt        | dd       S dS )zNormalize socket address to ASGI-compatible (host, port) tuple.

    ASGI spec requires server/client to be (host, port) tuples.
    IPv6 sockets return 4-tuples (host, port, flowinfo, scope_id),
    so we extract just the first two elements.
    N   )tuple)sockaddrs    O/var/www/descvideos/venv/lib/python3.12/site-packages/gunicorn/asgi/protocol.py_normalize_sockaddrr      s     #+5"144    c                       e Zd ZdZd Zy)ASGIResponseInfoz;Simple container for ASGI response info for access logging.c                     || _         || _        g | _        |D ]d  \  }}t        |t              r|j                  d      }t        |t              r|j                  d      }| j                  j                  ||f       f y )Nlatin-1)statussentheaders
isinstancebytesdecodeappend)selfr   r   r   namevalues         r   __init__zASGIResponseInfo.__init__$   sp    	" 	/KD%$&{{9-%'Y/LLu.	/r   N)__name__
__module____qualname____doc__r    r   r   r   r   !   s
    E
/r   r   c                       e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Zd Zd Zd Zd ZddZd Zd Zd Zd Zd Zd Zd Zy)ASGIProtocolzHTTP/1.1 protocol handler for ASGI applications.

    Handles connection lifecycle, request parsing, and ASGI app invocation.
    c                     || _         |j                  | _        |j                  | _        |j                  | _        d | _        d | _        d | _        d | _        d| _	        d| _
        d | _        y )Nr   F)workercfglogasgiapp	transportreaderwriter_task	req_count_closed_receive_queue)r   r'   s     r   r   zASGIProtocol.__init__7   s^    ::::;;
 "r   c                    || _         | j                  xj                  dz  c_        |j                  d      }|rut	        |d      ri|j                         }|dk(  rTt        j                         | _        | j                  j                  j                  | j                  ||            | _        yt        j                         | _        || _        | j                  j                  j                  | j                               | _        y)z(Called when a connection is established.   
ssl_objectselected_alpn_protocolh2N)r,   r'   nr_connsget_extra_infohasattrr6   asyncioStreamReaderr-   loopcreate_task_handle_http2_connectionr/   r.   _handle_connection)r   r,   r5   alpns       r   connection_madezASGIProtocol.connection_madeG   s    "! --l;
'*.FG446Dt| &224![[--9911)ZH
  **, [[%%11$2I2I2KL
r   c                 T    | j                   r| j                   j                  |       yy)z/Called when data is received on the connection.N)r-   	feed_data)r   datas     r   data_receivedzASGIProtocol.data_receiveda   s     ;;KK!!$' r   c                 &   | j                   ryd| _         | j                  xj                  dz  c_        | j                  r| j                  j	                          | j
                  | j
                  j                  ddi       | j                  r| j                  j                         sht        | j                  dd      }|dkD  r1| j                  j                  j                  || j                         y| j                  j                          yyy)	a  Called when the connection is lost or closed.

        Instead of immediately cancelling the task, we signal a disconnect
        event and send an http.disconnect message to the receive queue.
        This allows the ASGI app to clean up resources (like database
        connections) gracefully before the task is cancelled.

        See: https://github.com/benoitc/gunicorn/issues/3484
        NTr4   typehttp.disconnectasgi_disconnect_grace_period   r   )r1   r'   r8   r-   feed_eofr2   
put_nowaitr/   donegetattrr(   r=   
call_later_cancel_task_if_pendingcancel)r   excgrace_periods      r   connection_lostzASGIProtocol.connection_lostf   s     <<!;;KK  " ***F4E+FG ::djjoo/"488-KQOLa  ++ 00 

!!# 0:r   c                     | j                   r6| j                   j                         s| j                   j                          yyy)z9Cancel the task if it's still pending after grace period.N)r/   rN   rR   r   s    r   rQ   z$ASGIProtocol._cancel_task_if_pending   s-    ::djjoo/JJ 0:r   c                 >   	 | j                   j                  |       y# t        $ re}|j                  t        j                  t        j
                  t        j                  fvr | j                  j                  d       Y d}~yY d}~yd}~wt        t        f$ r Y yw xY w)ax  Write data to transport, handling connection errors gracefully.

        Catches exceptions that occur when the client has disconnected:
        - OSError with errno EPIPE, ECONNRESET, ENOTCONN
        - RuntimeError when transport is closing/closed
        - AttributeError when transport is None

        These are silently ignored since the client is already gone.
        zSocket error writing response.N)r,   writeOSErrorerrnoEPIPE
ECONNRESETENOTCONNr)   	exceptionRuntimeErrorAttributeError)r   rE   es      r   _safe_writezASGIProtocol._safe_write   sw    	NN  & 	Ewwu{{E,<,<ennMM""#CDD Nn- 		s    	BABBBc                   K   t        | j                        }	 | j                  j                  d      }| j                  j                  d      }| j                  s| xj
                  dz  c_        	 t        | j                  dd      }|dk(  r5t        j                  | j                  ||| j
                         d{   }n4t        j                  | j                  ||| j
                         d{   }| j                  |      r| j!                  |||       d{    n| j#                  |||       d{   }| j$                  xj&                  dz  c_        | j$                  j&                  | j$                  j(                  k\  r.| j                  j+                  d	       d
| j$                  _        d
}|r| j$                  j,                  sn=| j                  j.                  sn&|j1                          d{    | j                  s| j;                          y7 c7 1# t        $ r Y "t        $ r&}| j                  j                  d|       Y d}~Kd}~ww xY w7 D7 +7 k# t2        j4                  $ r Y pt6        $ r&}| j                  j9                  d|       Y d}~d}~ww xY w# | j;                          w xY ww)z/Main request handling loop for this connection.peernamesocknamer4   protocolhttpuwsgiNzuWSGI parse error: %s,Autorestarting worker after current request.FzError handling connection: %s)r   r-   r,   r9   r1   r0   rO   r(   r   parser   r   r   r)   debug_is_websocket_upgrade_handle_websocket_handle_http_requestr'   nrmax_requestsinfoalive	keepalive
drain_bodyr;   CancelledError	Exceptionr_   _close_transport)r   unreaderre   rf   rg   requestrb   rt   s           r   r@   zASGIProtocol._handle_connection   sP     -A	$~~44Z@H~~44Z@Hll!#&txxVDH7*(9(?(? HH$$ NN	) # )5(:(: HH$$ NN	) # --g600(HMMM #'";";Xx# 	
 !# ;;>>T[[%=%==HHMM"PQ(-DKK% %I (9(9 xx)) ((***m llz !!#m## " * HHNN#:A> N* +%% 	 	CHH>BB	C !!#s   KAI* 2AH& =H >4H& 2H#3H& 7'I* I"I* :I%;CI* <I(=I* K H& #H& &	I/I* 1I9II* II* %I* (I* *J-=J0 ?J-J(#J0 (J--J0 0KKc                     |j                   dk7  ryd}d}|j                  D ]1  \  }}|dk(  r|j                         }|dk(  s"|j                         }3 |dk(  xr |xr d|v S )a	  Check if request is a WebSocket upgrade.

        Per RFC 6455 Section 4.1, the opening handshake requires:
        - HTTP method MUST be GET
        - Upgrade header MUST be "websocket" (case-insensitive)
        - Connection header MUST contain "Upgrade"
        GETFNUPGRADE
CONNECTION	websocketupgrade)methodr   lower)r   rz   r   
connectionr   r   s         r   rm   z"ASGIProtocol._is_websocket_upgrade   sv     >>U"
"?? 	+KD%y ++-%"[[]
		+
 +%P*Pj9PPr   c                    K   ddl m} | j                  |||      } || j                  | j                  || j
                  | j                        }|j                          d{    y7 w)z!Handle WebSocket upgrade request.r   )WebSocketProtocolN)gunicorn.asgi.websocketr   _build_websocket_scoper,   r-   r+   r)   run)r   rz   rf   re   r   scopews_protocols          r   rn   zASGIProtocol._handle_websocket   sT     =++GXxH'NNDKK$((
 oos   A!A+#A)$A+c           	      	   K    j                  ||      }dddddg dt        j                          _        dj                  dk(  r,j
                  s j                  dddd       d{    dn%t        j                   j                                fd	} f	d
} j                  ||      }d}	 t        j                         }	 j                  j                   j                          j                  |||       d{    s j!                  dd       d{    dd _        	 t        j                         |	z
  }
t)              } j$                  j+                  |||
        j                  j-                   j                  ||       j3                         ry j                  j4                  xr  j                  j6                  S 7 7 7 # t        j"                  $ r  j$                  j'                  d       Y d _        	 t        j                         	z
  }
t)              } j$                  j+                  |||
        j                  j-                   j                  ||       y# t.        $ r  j$                  j1                  d       Y yw xY wt.        $ r  j$                  j1                  d       s j!                  dd       d{  7   dY d _        	 t        j                         	z
  }
t)              } j$                  j+                  |||
        j                  j-                   j                  ||       y# t.        $ r  j$                  j1                  d       Y yw xY ww xY w# t.        $ r  j$                  j1                  d       Y w xY w# d _        	 t        j                         	z
  }
t)              } j$                  j+                  |||
        j                  j-                   j                  ||       w # t.        $ r  j$                  j1                  d       Y w w xY wxY ww)zHandle a single HTTP request.FN  r   http.requestr   rH   body	more_bodyTc                     K   j                   rrddiS j                          d {   } | j                  d      dk(  r| j                  dd      sd| S 7 .w)NrH   rI   r   r   T)r1   get)msgbody_completereceive_queuer   s    r   receivez2ASGIProtocol._handle_http_request.<locals>.receive%  s]      || 122%))++C wwv.0d9S $J ,s   &AA/Ac                   	K   j                   ry | d   }|dk(  r?| j                  d      }| j                  dg       }j                  ||       d {    y |dk(  rwrt        d      y d| d   | j                  dg       
t	        d 
D              }|s j
                  d	k\  rdt        
      d
gz   
j                  
       d {    y |dk(  rst        d      y 	rt        d      y | j                  dd      }| j                  dd      }|r)j                  |       d {    t        |      z  |srj                  d       d	y y y 7 7 7 1w)NrH   http.response.informationalr   r   http.response.startResponse already startedTc              3      K   | ]o  \  }}t        |t              r|j                         n|j                         d k(  xs3 t        |t              r|j                         n|j                         dk(   q yw)s   content-lengthzcontent-lengthN)r   strr   ).0r   _s      r   	<genexpr>zBASGIProtocol._handle_http_request.<locals>.send.<locals>.<genexpr>N  sg      )  a &0c%:TZZ\

Qbb e(24(=

4::<Tdde)s   A5A7r4   r4   )s   transfer-encodings   chunkedhttp.response.bodyResponse not startedResponse already completer   r   r   F)chunkeds   0

)r1   r   _send_informationalr`   anyversionlist_send_response_start
_send_bodylenrc   )messagemsg_typeinfo_statusinfo_headershas_content_lengthr   r   exc_to_raiserz   response_completeresponse_headersresponse_sentresponse_startedresponse_statusr   use_chunkeds          r   sendz/ASGIProtocol._handle_http_request.<locals>.send3  s     ||vH88%kk(3&{{9b9..{L'RRR00##/0J#KL#' ")("3#*;;y"#=  &) ) $4) &" *goo.G"&K'+,<'=Ac@d'd$//AQSZ[[[11'#/0F#GL$#/0K#LL{{63/#KKU;	//$/DDD!SY.M "((6(,%	 ! 23 S. \ Es8   AE'E A;E'E#A"E'3E%4-E'#E'%E'Internal Server Errorz'Request cancelled (client disconnected)Exception in post_request hookError in ASGI application)_build_http_scoper;   Queuer2   content_lengthr   putr>   _read_body_to_queue_build_environr   nowr(   pre_requestr'   r+   _send_error_responserv   r)   rl   r   accesspost_requestrw   r_   should_closers   rt   )r   rz   rf   re   r   r   r   environresprequest_startrequest_timer   r   r   r   r   r   r   r   r   s   ``         @@@@@@@@@r   ro   z!ASGIProtocol._handle_http_request  s    &&w(C !   + !!Q&w##&"%   
 !M  8 8- PQ	;	- ;	-| %%gxB#	E$LLNMHH  g6((5'4000'"" $//5LMMM"% #'DE'||~='9I=YgwE%%dkk7GTJ
 !{{  7TXX%7%77Ez 1 N %% 	HHNNDE #'DE'||~='9I=YgwE%%dkk7GTJ E""#CDE!  	HH:;#//5LMMM"% #'DE'||~='9I=YgwE%%dkk7GTJ E""#CDE!	   E""#CDE #'DE'||~='9I=YgwE%%dkk7GTJ E""#CDEs!  A2R?G> ARAH &H'H HH RA*N5 ?A RH H .N23O  4R<A*J' &R'$KRKR:N2LN2O  RA*N R$N.+R-N..R1N22O  5$OROR Q>)A*QQ>$Q;8Q>:Q;;Q>>Rc                 j  K   	 	 |j                  d       d{   }|r|j                  d|dd       d{    n|j                  dddd       d{    yX7 C7 &7 
# t        $ rD}| j                  j	                  d|       |j                  dddd       d{  7   Y d}~yd}~ww xY ww)	z.Read request body and put chunks on the queue.Ti   Nr   r   r   FzError reading body: %s)	read_bodyr   rw   r)   rl   )r   rz   queuechunkrb   s        r   r   z ASGIProtocol._read_body_to_queue  s     	%//66)) . %%)%     )) . #%*%   
  6  	HHNN3Q7))&"   	sl   B3A# AA# AA# A!A# B3A# A# !A# #	B0,4B+ B#!B+&B3+B00B3c                    g }|j                   D ]D  \  }}|j                  |j                         j                  d      |j                  d      f       F t	        |      }t	        |      }dddd|j
                  d    d|j
                  d    |j                  |j                  |j                  |j                  r|j                  j                  d      nd	|j                  r|j                  j                  d      nd	| j                  j                  xs d
|||d}	t        | j                  d      r| j                  j                  |	d<   t        |d      rd|j                  |j                   di|	d<   |	S )z*Build ASGI HTTP scope from parsed request.r   rh   3.02.4r   spec_versionr   .r4   r    rH   r*   http_versionr   schemepathraw_pathquery_string	root_pathr   serverclientstatepriority_weighthttp.response.priorityweight
depends_on
extensions)r   r   r   encoder   r   r   r   r   queryr(   r   r:   r'   r   r   priority_depends_on)
r   rz   rf   re   r   r   r   r   r   r   s
             r   r   zASGIProtocol._build_http_scope  s[    "?? 	VKD%NNDJJL//	:ELL<STU	V %X.$X.  %u=&q12!GOOA4F3GHnnnnLL:A,,++I6C?F}}GMM00;RU++1r
  4;;(![[..E'N 7-.(%55")"="=+#E, r   c           	         |j                   |j                  |j                  |j                  xs dd|j                  d    d|j                  d    |r|d   ndd}|j
                  D ]  \  }}d|j                  dd	      z   }|||<   ! |S )
z8Build minimal WSGI-like environ dict for access logging.r   HTTP/r   r   r4   -REQUEST_METHODRAW_URI	PATH_INFOQUERY_STRINGSERVER_PROTOCOLREMOTE_ADDRHTTP_r   )r   urir   r   r   r   replacer   rz   rf   re   r   r   r   keys           r   r   zASGIProtocol._build_environ  s     &nn{{ #MM/R!&wq'9&:!GOOA<N;OP*28A;
 #?? 	!KD%DLLc22C GCL	! r   c                 :   g }|j                   D ]D  \  }}|j                  |j                         j                  d      |j                  d      f       F g }|j                   D ]8  \  }}|dk(  s|j	                  d      D cg c]  }|j                          }} n t        |      }	t        |      }
dddd|j                  d    d	|j                  d
    |j                  dk(  rdnd|j                  |j                  r|j                  j                  d      nd|j                  r|j                  j                  d      nd| j                  j                  xs d||	|
|d}t        | j                  d      r| j                  j                  |d<   |S c c}w )z/Build ASGI WebSocket scope from parsed request.r   zSEC-WEBSOCKET-PROTOCOL,r   r   r   r   r   r   r4   httpswsswsr   r   )rH   r*   r   r   r   r   r   r   r   r   r   subprotocolsr   )r   r   r   r   splitstripr   r   r   r   r   r(   r   r:   r'   r   )r   rz   rf   re   r   r   r   r   sr   r   r   s               r   r   z#ASGIProtocol._build_websocket_scope  s}    "?? 	VKD%NNDJJL//	:ELL<STU	V "?? 	KD%//38;;s3CDa	DD	
 %X.$X.   %u=&q12!GOOA4F3GH&~~8edLL:A,,++I6C?F}}GMM00;RU++1r(
  4;;(![[..E'N3  Es   Fc           	        K   |j                   dk  ry| j                  |      }d|j                   d    d|j                   d    d| d| d	}|D ]R  \  }}t        |t              r|j	                  d	      }t        |t              r|j	                  d	      }|| d
| dz  }T |dz  }| j                  |j                  d	             yw)ao  Send an informational response (1xx) such as 103 Early Hints.

        Args:
            status: HTTP status code (100-199)
            headers: List of (name, value) header tuples
            request: The parsed request object

        Note: Informational responses are only sent for HTTP/1.1 or later.
        HTTP/1.0 clients do not support 1xx responses.
        r   Nr   r   r   r4    
r   : )r   _get_reason_phraser   r   r   rc   r   )r   r   r   rz   reasonresponser   r   s           r   r   z ASGIProtocol._send_informational  s      ??V#((07??1-.a0B/C1VHAfXUYZ" 	/KD%$&{{9-%'Y/4&5'..H	/ 	F34s   CC
c           	        K   | j                  |      }d|j                  d    d|j                  d    d| d| d	}g }|D ]^  \  }}t        |t              r|j	                  d      }t        |t              r|j	                  d      }|j                  | d| d       ` |j                  d	       |d
j                  |      z   dz   }	| j                  |	j                  d             yw)z&Send HTTP response status and headers.r   r   r   r4   r  r  r   r  zServer: gunicorn/asgi
r   N)	r  r   r   r   r   r   joinrc   r   )
r   r   r   rz   r  status_lineheader_linesr   r   r  s
             r   r   z!ASGIProtocol._send_response_start5  s      ((0gooa017??13E2FaxqQWPXX\] " 	8KD%$&{{9-%'Y/4&5' 67	8 	78!66?34s   C)C+c                    K   |rJ|r6t        |      ddj                  d      |z   dz   }| j                  |       y| j                  |       yyw)zSend response body chunk.xr  r   s   
N)r   r   rc   )r   r   r   r   s       r   r   zASGIProtocol._send_bodyK  sT     t9Q-t,33I>EO  '  & s   AAc                    K   |j                  d      }d| d| dt        |       d}| j                  |j                  d             | j                  |       yw)zSend an error response.zutf-8z	HTTP/1.1 r  z,
Content-Type: text/plain
Content-Length: z
Connection: close

r   N)r   r   rc   )r   r   r   r   r  s        r   r   z!ASGIProtocol._send_error_responseU  se     ~~g&xq	 *"4yk * 	 	34s   AAc                     i ddddddddd	d
dddddddddddddddddddddd d!d"i d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;d<d=d>d?d@dAdB}|j                  |dC      S )Dz'Get HTTP reason phrase for status code.d   Continuee   zSwitching Protocolsg   zEarly Hints   OK   Created   Accepted   z
No Content   zPartial Contenti-  zMoved Permanentlyi.  Foundi/  z	See Otheri0  zNot Modifiedi3  zTemporary Redirecti4  zPermanent Redirecti  zBad Requesti  Unauthorizedi  	Forbiddeni  z	Not Foundi  zMethod Not Allowedi  zRequest Timeouti  Conflicti  Gonei  zLength Requiredi  zPayload Too Largei  zURI Too Longi  zUnsupported Media Typei  zUnprocessable Entityi  zToo Many Requestsr   r   i  zNot Implementedi  zBad Gatewayi  zService Unavailablei  zGateway TimeoutUnknown)r   )r   r   reasonss      r   r  zASGIProtocol._get_reason_phraseb  s   "
"
&"
 "
 	"

 "
 "
 "
 ""
 $"
 "
 "
 "
 %"
 %"
 "
  !"
" #"
$ %"
& %'"
( ")"
* +"
, -"
. "/"
0 $1"
2 3"
4 )5"
6 '7"
8 $9"
: (;"
< "="
> ?"
@ &A"
B "C"
F {{69--r   c                    | j                   rd| j                  sW	 | j                   j                         r| j                   j                          | j                   j	                          d| _        yyy# t
        $ r Y w xY w)zClose the transport safely.

        Calls write_eof() first if supported to signal end of writing,
        which helps ensure buffered data is flushed before closing.
        TN)r,   r1   can_write_eof	write_eofcloserw   rW   s    r   rx   zASGIProtocol._close_transport  sj     >>$,,>>//1NN,,.$$&  DL #/>  s   AA2 2	A>=A>c           	        K   	 ddl m} |j                  d      }|j                  d      }| j                  }t	        j
                  |      }t	        j                  |||| j                  j                        } || j                  |||      }	|	j                          d{    |	| _        |	j                  s!| j                  j                  r
	 |	j                  d       d{   }
|
D ]D  }	 | j'                  ||	||       d{    |	j3                  |j,                  j.                         F | j                  xj4                  t7        |
      z  c_        | j                  j4                  | j                  j8                  k\  r-| j"                  j;                  d       d| j                  _        n$|	j                  s| j                  j                  r
t?        | d      r#	 | j                  jA                          d{    | jC                          y7 z7 7# t        j                  $ r Y t         $ r&}| j"                  j%                  d|       Y d}~d}~ww xY w7 _# t         $ rp}| j"                  j)                  d	       	 |	j+                  |j,                  j.                  d
t1        |             d{  7   n# t         $ r Y nw xY wY d}~d}~ww xY w# |	j3                  |j,                  j.                         w xY w# t        j<                  $ r Y Lt         $ r'}| j"                  j)                  d|       Y d}~vd}~ww xY w7 T# t         $ r Y ^w xY w# t?        | d      r4	 | j                  jA                          d{  7   n# t         $ r Y nw xY w| jC                          w xY ww)zHandle an HTTP/2 connection.r   )AsyncHTTP2Connectionre   rf   Ng      ?)timeoutzHTTP/2 receive error: %szError handling HTTP/2 requestr   rj   FzHTTP/2 connection error: %s_h2_conn)"gunicorn.http2.async_connectionr)  r9   r-   r;   StreamReaderProtocolStreamWriterr'   r=   r(   initiate_connectionr+  	is_closedrs   receive_dataTimeoutErrorrw   r)   rl   _handle_http2_requestr_   
send_errorstream	stream_idr   cleanup_streamrp   r   rq   rr   rv   r:   r'  rx   )r   r,   r5   r)  re   rf   r-   rg   r.   h2_connrequestsrb   reqs                r   r?   z%ASGIProtocol._handle_http2_connection  s0    C	$L //
;H //
;H [[F33F;H))8VT[[-=-=F
 +&&(G --///#DM ''DKK,=,=%,%9%9#%9%FFH $ ECE"88(H    ..szz/C/CDE" #h-/ ;;>>T[[%=%==HHMM"PQ(-DKK%A ''DKK,=,=N tZ(----/// !!#c 0  G++   HHNN#=qA % !**+JK!")"4"4 #

 4 4c3q6#    ) ! !!  ..szz/C/CD %% 	 	AHH<a@@	A
 0   tZ(----///  !!#s  OBL !H"/L H! 'H(H! ,L 2I+	I(
I+CL O(M MM 
OL H! !I%4L 7I%?I L  I%%L (I++	K$4K3K
KK
	K
	KKKKK'K$$K'''LL M$M, 'M/MM, MM, M 	M)%O(M))O,N>:NNNN>	N*'N>)N**N>>Oc           	         K   j                   j                  | j                  ||      }ddddg dg fd}f	d}| j                  ||      }t	        j
                         }		 | j                  j                  | j                         | j                  |||       d{    rg }
D ]Z  \  }}t        |t              r|j                  d      }t        |t              r|j                  d      }|
j                  ||f       \ r dt              fg}|
D ]/  \  }}|j                  |j                         t        |      f       1 j                   j#                  |d	       j$                     }|j#                  |d	       j'                          d{    rIj                   j)                  d	       |j)                  d	       j'                          d{    j+                         d{    n:j-                  |
       d{    nj/                  dd
       d{    d	 t	        j
                         |	z
  }t7        t9                    }| j2                  j;                  |||       | j                  j=                  | j                  ||       y7 7 7 7 7 7 # t0        $ r> | j2                  j5                  d       sj/                  dd
       d{  7   dY w xY w# t0        $ r | j2                  j5                  d       Y yw xY w# 	 t	        j
                         |	z
  }t7        t9                    }| j2                  j;                  |||       | j                  j=                  | j                  ||       w # t0        $ r | j2                  j5                  d       Y w w xY wxY ww)zHandle a single HTTP/2 request.FNr   r   c                  L   K   j                   j                         } d| ddS w)Nr   Fr   )r   read)r   rz   s    r   r   z3ASGIProtocol._handle_http2_request.<locals>.receive  s,     <<$$&D&" s   !$c                   	K   | d   }|dk(  r| j                  d      }| j                  dg       }g }|D ]Z  \  }}t        |t              r|j                  d      }t        |t              r|j                  d      }|j	                  ||f       \ j                  ||       d {    y |dk(  r(rt        d      y d| d   | j                  dg       y |d	k(  rMst        d
      y rt        d      y | j                  dd      }| j                  dd      }|r|z  |sdy y |dk(  rst        d      y | j                  dg       }	g }
|	D ]Z  \  }}t        |t              r|j                  d      }t        |t              r|j                  d      }|
j	                  ||f       \ j                  |
       y y 7 w)NrH   r   r   r   r   r   r   Tr   r   r   r   r   r   Fhttp.response.trailersz)Cannot send trailers before body complete)r   r   r   r   r   send_informationalr`   extend)r   r   r   r   r   r   r   r   r   trailer_headerstrailersr   r8  response_bodyr   r   r   r   response_trailersr6  s              r   r   z0ASGIProtocol._handle_http2_request.<locals>.send  s     vH88%kk(3&{{9b9#/ 2KD%!$.#{{95!%/ %Y 7NND%=12 00KQQQ00##/0J#KL#' ")("3#*;;y"#= 11'#/0F#GL$#/0K#LL{{63/#KKU;	!T)M (,% ! 55(#/0[#\L")++i"<#2 3KD%!$.#{{95!%/ %Y 7OOT5M23 "((2 69 Rs   B%G	(G)DG	r   z:status)
end_streamr   r   r   )r5  r6  _build_http2_scope_build_http2_environr   r   r(   r   r'   r+   r   r   r   r   r   r   r8  send_headersstreams_send_pending_data	send_datasend_trailerssend_responser4  rw   r)   r_   r   r   r   r   )r   rz   r8  rf   re   r   r   r   r   r   r   r   r   response_hdrsr5  r   r   r   rD  r   r   r   r   rE  r6  s    ``              @@@@@@@@r   r3  z"ASGIProtocol._handle_http2_request  s    NN,,	''8D !	;	3 ;	3| ++GXxH <	EHH  g6((5'4000'""  #3 2KD%!$.#{{95!%/ %Y 7NND%=12 %&/_1E%F$GM'. Ie%,,djjlCJ-GHI OO00MV[0\$__Y7F''%'H!44666 %11)]W\1]((5(I%88::: "//	;LMMM!//!?G]   ((C9PQQQ"%E'||~='#%5s=7I gwE%%dkk7GTJq 14 7 ; N R  	&HH:;#((C9PQQQ"%		&  E""#CDEE'||~='#%5s=7I gwE%%dkk7GTJ E""#CDEs   A1O>><K' :K;DK' ?K A
K' 
KK' $K!%K' K#K' K%K' %A3L1 O>K' K' K' !K' #K' %K' '<L.#L&$L.+M -L..M 1$MO>MO>O;A3OO;$O85O;7O88O;;O>c                    g }|j                   D ]D  \  }}|j                  |j                         j                  d      |j                  d      f       F t	        |      }t	        |      }ddddd|j
                  |j                  |j                  |j                  r|j                  j                  d      nd|j                  r|j                  j                  d      nd| j                  j                  xs d|||d	}	t        | j                  d
      r| j                  j                  |	d
<   i }
t        |d      r|j                  |j                  d|
d<   i |
d<   |
|	d<   |	S )z*Build ASGI HTTP scope from HTTP/2 request.r   rh   r   r   r   2r   r   r   r   r   r   r   r?  r   )r   r   r   r   r   r   r   r   r   r(   r   r:   r'   r   r   r   )r   rz   rf   re   r   r   r   r   r   r   r   s              r   rG  zASGIProtocol._build_http2_scopev  sQ   "?? 	KD%NN

##I.Y' 	 %X.$X.  %u=nnnnLL:A,,++I6C?F}}GMM00;RU++1r
 4;;(![[..E'N 
7-.!11%994J/0
 02
+,(lr   c                     |j                   |j                  |j                  |j                  xs dd|r|d   ndd}|j                  D ]  \  }}d|j                  dd      z   }|||<   ! |S )z.Build minimal environ dict for access logging.r   zHTTP/2r   r   r   r   r   )r   r   r   r   r   r   r   s           r   rH  z!ASGIProtocol._build_http2_environ  sx     &nn{{ #MM/R'*28A;
 #?? 	!KD%DLLc22C GCL	! r   N)F)r   r    r!   r"   r   rB   rF   rU   rQ   rc   r@   rm   rn   ro   r   r   r   r   r   r   r   r   r  rx   r?   r3  rG  rH  r#   r   r   r%   r%   1   s    
# M4(
!$F 
&E$NQ* V8p4&P$$L585,'%.N  E$NTEl)Vr   r%   )r"   r;   r[   r   gunicorn.asgi.unreaderr   gunicorn.asgi.messager   gunicorn.asgi.uwsgir   gunicorn.http.errorsr   gunicorn.uwsgi.errorsr   r   r   Protocolr%   r#   r   r   <module>rY     sG   
    0 . 1 + 55/ / 7## r   