o
    Á¿i—!  ã                   @   sB   d dl Z d dlmZmZ d dlmZmZmZ dZG dd„ dƒZ	dS )é    N)ÚLengthReaderÚBody)ÚInvalidUWSGIHeaderÚUnsupportedModifierÚForbiddenUWSGIRequestiè  c                   @   sZ   e Zd ZdZd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dS )ÚUWSGIRequestaù  uWSGI protocol request parser.

    The uWSGI protocol uses a 4-byte binary header:
    - Byte 0: modifier1 (packet type, 0 = WSGI request)
    - Bytes 1-2: datasize (16-bit little-endian, size of vars block)
    - Byte 3: modifier2 (additional flags, typically 0)

    After the header:
    1. Vars block (datasize bytes): Key-value pairs containing WSGI environ
       - Each pair: 2-byte key_size (LE) + key + 2-byte val_size (LE) + value
    2. Request body (determined by CONTENT_LENGTH in vars)
    é   c                 C   s´   || _ || _|| _|| _|| _d | _d | _d | _d | _d| _	d| _
g | _g | _d | _|jr/dnd| _d| _i | _d| _d| _d | _d| _|  ¡  |  | j¡}| j |¡ |  ¡  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Ú_expected_100_continueÚ_check_allowed_ipÚparseÚunreadÚset_body_reader)Úselfr   r   r   r   Úunused© r(   úJ/home/ubuntu/.local/lib/python3.10/site-packages/gunicorn/uwsgi/message.pyÚ__init__!   s2   zUWSGIRequest.__init__c                 C   sN   t | jdddgƒ}t| jtƒsdS d|v rdS | jd |vr%t| jd ƒ‚dS )z(Verify source IP is in the allowed list.Úuwsgi_allow_ipsz	127.0.0.1z::1NÚ*r   )Úgetattrr   Ú
isinstancer   Útupler   )r&   Ú	allow_ipsr(   r(   r)   r"   H   s   ÿzUWSGIRequest._check_allowed_ipc                 C   s
   d| _ dS )z1Force the connection to close after this request.TN)r   )r&   r(   r(   r)   Úforce_closeW   s   
zUWSGIRequest.force_closec                 C   sš   |   |d¡}t|ƒdk rtdƒ‚|d | _t |dd… d¡}|d | _| jdkr.t| jƒ‚|dkrG|   ||¡}t|ƒ|k rBtdƒ‚|  |¡ |  	¡  dS )	z)Parse uWSGI packet header and vars block.é   zincomplete headerr   r   é   Úlittlezincomplete vars blockó    )
Ú_read_exactÚlenr   r   ÚintÚ
from_bytesr   r   Ú_parse_varsÚ_extract_request_info)r&   r   ÚheaderÚdatasizeÚ	vars_datar(   r(   r)   r#   [   s   




zUWSGIRequest.parsec                 C   sv   t  ¡ }|}|dkr | ¡ }|sn| |¡ || ¡  }|dks
| ¡ }t|ƒ|kr9| ||d… ¡ |d|… }|S )z*Read exactly size bytes from the unreader.r   N)ÚioÚBytesIOÚreadÚwriteÚtellÚgetvaluer7   r$   )r&   r   ÚsizeÚbufÚ	remainingÚdataÚresultr(   r(   r)   r6   v   s   
ûzUWSGIRequest._read_exactc                 C   s&  d}d}|t |ƒk r‘|tkrtdƒ‚|d t |ƒkrtdƒ‚t |||d … d¡}|d7 }|| t |ƒkr:tdƒ‚|||| …  d¡}||7 }|d t |ƒkrUtdƒ‚t |||d … d¡}|d7 }|| t |ƒkrqtd	ƒ‚|||| …  d¡}||7 }|| j|< |d
7 }|t |ƒk s
dS dS )z‚Parse uWSGI vars block into key-value pairs.

        Format: key_size (2 bytes LE) + key + val_size (2 bytes LE) + value
        r   ztoo many variablesé   ztruncated key sizer4   ztruncated keyzlatin-1ztruncated value sizeztruncated valuer   N)r7   ÚMAX_UWSGI_VARSr   r8   r9   Údecoder   )r&   rH   ÚposÚ	var_countÚkey_sizeÚkeyÚval_sizeÚvaluer(   r(   r)   r:   Š   s0   
ãzUWSGIRequest._parse_varsc                 C   s   | j  dd¡| _| j  dd¡| _| j  dd¡| _| jr%d| j| jf | _n| j| _| j  dd¡ ¡ d	v r8d
| _nd| j v rC| j d | _| j  ¡ D ]5\}}| 	d¡rd|dd…  
dd¡}| j ||f¡ qH|dkrq| j d|f¡ qH|dkr}| j d|f¡ qHdS )a  Extract HTTP request info from uWSGI vars.

        Header Mapping (CGI/WSGI to HTTP):

        The uWSGI protocol passes HTTP headers using CGI-style environment
        variable naming. This method converts them back to HTTP header format:

        - HTTP_* vars: Strip 'HTTP_' prefix, replace '_' with '-'
          Example: HTTP_X_FORWARDED_FOR -> X-FORWARDED-FOR
          Example: HTTP_ACCEPT_ENCODING -> ACCEPT-ENCODING

        - CONTENT_TYPE: Mapped directly to CONTENT-TYPE header
          (CGI spec excludes HTTP_ prefix for this header)

        - CONTENT_LENGTH: Mapped directly to CONTENT-LENGTH header
          (CGI spec excludes HTTP_ prefix for this header)

        Note: The underscore-to-hyphen conversion is lossy. Headers that
        originally contained underscores (e.g., X_Custom_Header) cannot be
        distinguished from hyphenated headers (X-Custom-Header) after
        passing through nginx/uWSGI. This is a CGI/WSGI specification
        limitation, not specific to this implementation.
        ÚREQUEST_METHODÚGETÚ	PATH_INFOú/ÚQUERY_STRINGr	   z%s?%sÚHTTPS)ÚonÚ1Útruer
   zwsgi.url_schemeÚHTTP_é   NÚ_ú-ÚCONTENT_TYPEzCONTENT-TYPEÚCONTENT_LENGTHzCONTENT-LENGTH)r   Úgetr   r   r   r   Úlowerr   ÚitemsÚ
startswithÚreplacer   Úappend)r&   rP   rR   Úheader_namer(   r(   r)   r;   ±   s(   

€øz"UWSGIRequest._extract_request_infoc                 C   sT   d}d| j v rztt| j d ƒdƒ}W n ty   d}Y nw tt| j|ƒƒ| _dS )z/Set up the body reader based on CONTENT_LENGTH.r   ra   N)r   Úmaxr8   Ú
ValueErrorr   r   r   r   )r&   Úcontent_lengthr(   r(   r)   r%   è   s   
ÿzUWSGIRequest.set_body_readerc                 C   s8   | j rdS | j dd¡ ¡ }|dkrdS |dkrdS dS )z@Determine if the connection should be closed after this request.TÚHTTP_CONNECTIONr	   Úclosez
keep-aliveF)r   r   rb   rc   )r&   Ú
connectionr(   r(   r)   Úshould_closeõ   s   zUWSGIRequest.should_closeN)r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r*   r"   r1   r#   r6   r:   r;   r%   ro   r(   r(   r(   r)   r      s    
''7r   )
r?   Úgunicorn.http.bodyr   r   Úgunicorn.uwsgi.errorsr   r   r   rK   r   r(   r(   r(   r)   Ú<module>   s
   