a cg@sdddlmZmZmZmZmZmZmZmZm Z ddl m Z m Z m Z mZmZmZmZddlmZmZmZddlmZmZddlmZddlmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%ddl&m'Z'm(Z(m)Z)dd l*m+Z+m,Z,gd Z-Gd d d e)e)d Z.Gddde)e)d Z/dZ0e eefe1dddZ2e3e eefee4e edee5ffdddZ6GdddZ7dS)) AnyCallablecastDictListOptionalTupleTypeUnion)ConnectionClosedData EndOfMessageEventInformationalResponseRequestResponse)get_comma_headerhas_expect_100_continueset_comma_header)READERS ReadersType) ReceiveBuffer) _SWITCH_CONNECT_SWITCH_UPGRADECLIENTConnectionStateDONEERRORMIGHT_SWITCH_PROTOCOL SEND_BODYSERVERSWITCHED_PROTOCOL)LocalProtocolErrorRemoteProtocolErrorSentinel)WRITERS WritersType) Connection NEED_DATAPAUSEDc@s eZdZdS)r)N__name__ __module__ __qualname__r/r/\/workspaces/shunt/resources/test-fastapi/venv/lib/python3.9/site-packages/h11/_connection.pyr)(sr)) metaclassc@s eZdZdS)r*Nr+r/r/r/r0r*,sr*i@eventreturncCs0t|jd}d|vrdSt|dddkr,dSdS)N connectioncloseF http_version1.1T)rheadersgetattr)r3 connectionr/r/r0 _keep_aliveHs  r<r/)request_methodr3r4cCst|ttfvsJt|turf|jdvsT|dksT|dkrXd|jkrPdkrXnndS|jdksfJt|jd}|r|dgksJd St|jd }|rd t|d ffSt|turdSd SdS)N)i0HEADCONNECT,)content-length)rtransfer-encodingchunked)chunkedr/content-lengthrCr)http/1.0r/)typerr status_coderr9int)r=r3Ztransfer_encodingsZcontent_lengthsr/r/r0 _body_framingQs0     rLc@seZdZdZefeeeddddZe e eeeefdddZ e eedd d Z e eedd d Z e edd dZddddZeeddddZeeeedddZeeeddddZeeeeeeefeedefdddZd3e eeeefeedddd Ze eeefdd!d"Zedd#d$d%Z eeee!ee"fdd&d'Z#eeee!ee"fdd(d)Z$eeedd*d+Z%eee&edd,d-Z'ddd.d/Z(e)e)d0d1d2Z*dS)4r(aBAn object encapsulating the state of an HTTP connection. Args: our_role: If you're implementing a client, pass :data:`h11.CLIENT`. If you're implementing a server, pass :data:`h11.SERVER`. max_incomplete_event_size (int): The maximum number of bytes we're willing to buffer of an incomplete event. In practice this mostly sets a limit on the maximum size of the request/response line + headers. If this is exceeded, then :meth:`next_event` will raise :exc:`RemoteProtocolError`. N)our_rolemax_incomplete_event_sizer4cCs||_|ttfvr td|||_||tur:t|_nt|_t|_| |jdt |_ | |jdt |_ t|_d|_d|_d|_d|_dS)Nz#expected CLIENT or SERVER, not {!r}F)_max_incomplete_event_sizerr! ValueErrorformatrM their_roler_cstate_get_io_objectr&_writerr_readerr_receive_buffer_receive_buffer_closedtheir_http_version_request_method"client_is_waiting_for_100_continue)selfrMrNr/r/r0__init__s  zConnection.__init__)r4cCs t|jjS)zA dictionary like:: {CLIENT: , SERVER: } See :ref:`state-machine` for details. )dictrSstatesr\r/r/r0r_s zConnection.statescCs|jj|jS)zjThe current state of whichever role we are playing. See :ref:`state-machine` for details. )rSr_rMr`r/r/r0 our_stateszConnection.our_statecCs|jj|jS)znThe current state of whichever role we are NOT playing. See :ref:`state-machine` for details. )rSr_rRr`r/r/r0 their_stateszConnection.their_statecCs|jtuo|jSN)rRrr[r`r/r/r0!they_are_waiting_for_100_continuesz,Connection.they_are_waiting_for_100_continuecCs4t|jj}|jd|_|jr&J||dS)aAttempt to reset our connection state for a new request/response cycle. If both client and server are in :data:`DONE` state, then resets them both to :data:`IDLE` state in preparation for a new request/response cycle on this same connection. Otherwise, raises a :exc:`LocalProtocolError`. See :ref:`keepalive-and-pipelining`. N)r^rSr_start_next_cyclerZr[_respond_to_state_changes)r\ old_statesr/r/r0res   zConnection.start_next_cycle)roler4cCs&t|jj}|j|||dSrc)r^rSr_Z process_errorrf)r\rhrgr/r/r0_process_errors  zConnection._process_errorr2cCsTt|tur|jdkrtSt|turPt|jjvrPd|jkrHdkrPnntSdS)NerArB)rIrrJrrrrSZpending_switch_proposals)r\r3r/r/r0_server_switch_events   zConnection._server_switch_event)rhr3r4cCs\t|jj}|turNt|turN|jdkr6|jtt |j drN|jt d}|t urd| |}|j|t||t|tur|j|_||jurt|tttfvrtttttf|}|j|_t|ttfvrtttttf|s|jt|turt|rd|_t|ttfvr*d|_|turLt|ttfvrLd|_|||dS)Nr@supgradeTF)r^rSr_rrIrmethodZprocess_client_switch_proposalrrr9rr!rkZ process_eventrZrRrrrr r7rYr<Zprocess_keep_alive_disabledrr[r rrf)r\rhr3rgZserver_switch_eventr/r/r0_process_events<        zConnection._process_event.)rhr3io_dictr4cCsZ|jj|}|turHttt|jtttt f|\}}|t||S| ||fSdSrc) rSr_r rLrbytesrZr rrget)r\rhr3rnstate framing_typeargsr/r/r0rT4s zConnection._get_io_object)rgr3r4cCsH|j||jkr"||j|t|_|j||jkrD||j|t|_dSrc) rarMrTr&rUrbrRrrV)r\rgr3r/r/r0rfJsz$Connection._respond_to_state_changescCst|j|jfS)abData that has been received, but not yet processed, represented as a tuple with two elements, where the first is a byte-string containing the unprocessed data itself, and the second is a bool that is True if the receive connection was closed. See :ref:`switching-protocols` for discussion of why you'd want this. )rorWrXr`r/r/r0 trailing_dataUs zConnection.trailing_data)datar4cCs,|r"|jrtd|j|7_nd|_dS)aAdd data to our internal receive buffer. This does not actually do any processing on the data, just stores it. To trigger processing, you have to call :meth:`next_event`. Args: data (:term:`bytes-like object`): The new data that was just received. Special case: If *data* is an empty byte-string like ``b""``, then this indicates that the remote side has closed the connection (end of file). Normally this is convenient, because standard Python APIs like :meth:`file.read` or :meth:`socket.recv` use ``b""`` to indicate end-of-file, while other failures to read are indicated using other mechanisms like raising :exc:`TimeoutError`. When using such an API you can just blindly pass through whatever you get from ``read`` to :meth:`receive_data`, and everything will work. But, if you have an API where reading an empty string is a valid non-EOF condition, then you need to be aware of this and make sure to check for such strings and avoid passing them to :meth:`receive_data`. Returns: Nothing, but after calling this you should call :meth:`next_event` to parse the newly received data. Raises: RuntimeError: Raised if you pass an empty *data*, indicating EOF, and then pass a non-empty *data*, indicating more data that somehow arrived after the EOF. (Calling ``receive_data(b"")`` multiple times is fine, and equivalent to calling it once.) z(received close, then received more data?TN)rX RuntimeErrorrW)r\rur/r/r0 receive_data`s 'zConnection.receive_datacCs|j}|tur|jrtS|tus(|tur,tS|jdus:J||j}|durx|jsx|jrxt|jdrr|j }nt }|durt }|S)Nread_eof) rbrrWr*rr"rVrXhasattrrxr r))r\rqr3r/r/r0_extract_next_receive_events    z&Connection._extract_next_receive_eventc Cs|jturtdz`|}|ttfvr<||jtt ||turnt |j |j kr`tddd|j rntd|WSty}z.||jt|tr|nWYd}~n d}~00dS)aFParse the next event out of our receive buffer, update our internal state, and return it. This is a mutating operation -- think of it like calling :func:`next` on an iterator. Returns: : One of three things: 1) An event object -- see :ref:`events`. 2) The special constant :data:`NEED_DATA`, which indicates that you need to read more data from your socket and pass it to :meth:`receive_data` before this method will be able to return any more events. 3) The special constant :data:`PAUSED`, which indicates that we are not in a state where we can process incoming data (usually because the peer has finished their part of the current request/response cycle, and you have not yet called :meth:`start_next_cycle`). See :ref:`flow-control` for details. Raises: RemoteProtocolError: The peer has misbehaved. You should close the connection (possibly after sending some kind of 4xx response). Once this method returns :class:`ConnectionClosed` once, then all subsequent calls will also return :class:`ConnectionClosed`. If this method raises any exception besides :exc:`RemoteProtocolError` then that's a bug -- if it happens please file a bug report! If this method raises any exception then it also sets :attr:`Connection.their_state` to :data:`ERROR` -- see :ref:`error-handling` for discussion. z+Can't receive data when peer state is ERRORzReceive buffer too longi)Zerror_status_hintz#peer unexpectedly closed connectionN)rbrr$rzr)r*rmrRrrlenrWrOrX BaseExceptionri isinstancer#Z!_reraise_as_remote_protocol_error)r\r3excr/r/r0 next_events&(     zConnection.next_eventcCs$||}|durdSd|SdS)aConvert a high-level event into bytes that can be sent to the peer, while updating our internal state machine. Args: event: The :ref:`event ` to send. Returns: If ``type(event) is ConnectionClosed``, then returns ``None``. Otherwise, returns a :term:`bytes-like object`. Raises: LocalProtocolError: Sending this event at this time would violate our understanding of the HTTP/1.1 protocol. If this method raises any exception then it also sets :attr:`Connection.our_state` to :data:`ERROR` -- see :ref:`error-handling` for discussion. N)send_with_data_passthroughjoin)r\r3 data_listr/r/r0sends zConnection.sendcCs|jturtdzbt|tur*||}|j}||j|t|t urPWdS|dus\Jg}|||j |WSWn| |jYn0dS)ahIdentical to :meth:`send`, except that in situations where :meth:`send` returns a single :term:`bytes-like object`, this instead returns a list of them -- and when sending a :class:`Data` event, this list is guaranteed to contain the exact object you passed in as :attr:`Data.data`. See :ref:`sendfile` for discussion. z'Can't send data when our state is ERRORN) rarr#rIr&_clean_up_response_headers_for_sendingrUrmrMr appendri)r\r3writerrr/r/r0rs         z%Connection.send_with_data_passthroughcCs||jdS)zNotify the state machine that we failed to send the data it gave us. This causes :attr:`Connection.our_state` to immediately become :data:`ERROR` -- see :ref:`error-handling` for discussion. N)rirMr`r/r/r0 send_failed'szConnection.send_failed)responser4cCst|tusJ|j}d}tt|j}|dkr2d}t||\}}|dvrt|dg}|jdush|jdkrt|dg}|jdkrd}nt|dd g}|j j r|rt t |d }| d |d t|d t|}t||j|j|jd S)NFr?sGET)rFrHrGr8rDTrEr5s keep-aliver6)r9rJr7reason)rIrr9rrorZrLrrYrS keep_alivesetrdiscardaddsortedrJr7r)r\rr9Z need_closeZmethod_for_choosing_headersrr_r;r/r/r0r@s2       z1Connection._clean_up_response_headers_for_sending)N)+r,r-r.__doc__!DEFAULT_MAX_INCOMPLETE_EVENT_SIZEr r%rKr]propertyrr_rarbboolrdrerirrrkrmr rr'rrrTrfrrortrwr)r*rzrrrrrrrr/r/r/r0r(sP '  2    0  A!r(N)8typingrrrrrrrr r Z_eventsr r rrrrr_headersrrr_readersrrZ_receivebufferr_staterrrrrrrr r!r"Z_utilr#r$r%_writersr&r'__all__r)r*rrr<rostrrKrLr(r/r/r/r0s ,$  0   :