o
    ie                  
   @   s  U 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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 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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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dl)m-Z- ddl)m.Z. ddl)m/Z/ dd l)m0Z1 dd!l)m2Z2 dd"l)m3Z4 dd#l)m5Z5 dd$l)m6Z6 dd%l)m7Z7 dd&l)m8Z8 dd'l)m9Z9 dd(l:m;Z; dd)l<m=Z= dd*l>m?Z? d+d,l@mAZA e;eBZCd-ZDed- eEd.< d/ZFed/ eEd0< d1ZGed1 eEd2< d3ZHed3 eEd4< d5ZIed5 eEd6< d7ZJed7 eEd8< d9ZKed9 eEd:< d;ZLed; eEd<< d=ZMed= eEd>< d?ZNed? eEd@< dAZOedA eEdB< dCZPedC eEdD< dEZQedE eEdF< dGZRedG eEdH< dIeSdJeTeS fdKdLZUeUeFZVeUeGZWeUeHZXeUeIZYeTeOeAeOZ gZ[eUeJZ\eUeKZ]eUeLZ^eUeMZ_eUeNZ`eUePZaeUeQZbeUeDZceUeRZdeedMejfZg	dldNeTeS dOeheSeSf dPeeS dJeeS fdQdRZidOeheSeSf dSefdTdUZjdVeSdJekfdWdXZlelZmdYekdJeSfdZd[Znd\eSd]eSdJdfd^d_ZoG d`da daZpG dbdc dcZqG ddde deZrG dfdg dgZsG dhdi diZte7epe5eqe6ere,ese+etiZuG djdk dkevZwdS )m    N)Literal)Optional)Union)SpanLink)Context)Span)!_get_64_highest_order_bits_as_hex) _get_64_lowest_order_bits_as_int)APPSEC)core)config)telemetry_writer)TELEMETRY_NAMESPACE   )	AUTO_KEEP)AUTO_REJECT)	USER_KEEP)TagsetDecodeError)TagsetEncodeError)TagsetMaxSizeDecodeError)TagsetMaxSizeEncodeError)decode_tagset_string)encode_tagset_valuesensure_text)_PROPAGATION_BEHAVIOR_RESTART)_PROPAGATION_STYLE_BAGGAGE)#_PROPAGATION_STYLE_W3C_TRACECONTEXT)BAGGAGE_TAG_PREFIX)DD_TRACE_BAGGAGE_MAX_BYTES)DD_TRACE_BAGGAGE_MAX_ITEMS)HIGHER_ORDER_TRACE_ID_BITS)LAST_DD_PARENT_ID_KEY)MAX_UINT_64BITS)PROPAGATION_STYLE_B3_MULTI)PROPAGATION_STYLE_B3_SINGLE)PROPAGATION_STYLE_DATADOG)W3C_TRACEPARENT_KEY)W3C_TRACESTATE_KEY)
get_logger)validate_sampling_decision)w3c_tracestate_add_p   )get_wsgi_headerzot-baggage-_HTTP_BAGGAGE_PREFIXzx-datadog-trace-idHTTP_HEADER_TRACE_IDzx-datadog-parent-idHTTP_HEADER_PARENT_IDzx-datadog-sampling-priorityHTTP_HEADER_SAMPLING_PRIORITYzx-datadog-originHTTP_HEADER_ORIGINb3_HTTP_HEADER_B3_SINGLEzx-b3-traceid_HTTP_HEADER_B3_TRACE_IDzx-b3-spanid_HTTP_HEADER_B3_SPAN_IDzx-b3-sampled_HTTP_HEADER_B3_SAMPLEDz
x-b3-flags_HTTP_HEADER_B3_FLAGSzx-datadog-tags_HTTP_HEADER_TAGStraceparent_HTTP_HEADER_TRACEPARENT
tracestate_HTTP_HEADER_TRACESTATEbaggage_HTTP_HEADER_BAGGAGEheaderreturnc                 C   s   t | t|  gS N)	frozensetr-   lower)r@    rE   L/home/ubuntu/.local/lib/python3.10/site-packages/ddtrace/propagation/http.py_possible_headerG   s   rG   aj  
     ^                  # Start of string
     ([a-f0-9]{2})-     # 2 character hex version
     ([a-f0-9]{32})-    # 32 character hex trace id
     ([a-f0-9]{16})-    # 16 character hex span id
     ([a-f0-9]{2})      # 2 character hex sample flag
     (-.+)?             # optional, start of any additional values
     $                  # end of string
     possible_header_namesheadersdefaultc                 C   s*   | D ]}||v rt || dd  S q|S )Nbackslashreplace)errorsr   )rH   rI   rJ   r@   rE   rE   rF   _extract_header_valuen   s
   rM   contextc                 C   sN   |d ur#|   D ]\}}tD ]}||r!||t|d  | qqd S d S rB   )items_POSSIBLE_HTTP_BAGGAGE_PREFIX
startswithset_baggage_itemlen)rI   rN   keyvaluepossible_prefixrE   rE   rF   _attach_baggage_to_contextx   s   
rW   hex_idc                 C   s
   t | dS )z7Helper to convert hex ids into Datadog compatible ints.   )int)rX   rE   rE   rF   _hex_id_to_dd_id      
r[   dd_idc                 C   s   | t kr	d| S d| S )zGHelper to convert Datadog trace/span int ids into lower case hex valuesz{:032x}{:016x})_MAX_UINT_64BITSformat)r]   rE   rE   rF   _dd_id_to_b3_id   s   

ra   metric_nameheader_stylec                 C   s   t jtj| dd|ffd dS )zRecord telemetry metric for HTTP propagation operations.

    :param metric_name: The name of the metric to record
    :param tags: tuple of tag key-value pairs to include with the metric
    r,   rc   	namespacenamerU   tagsN)r   add_count_metricr   TRACERS)rb   rc   rE   rE   rF   _record_http_telemetry   s   
rj   c                   @   s   e Zd ZdZedgZedd Zedee	e	f de
e	 fddZed	d
 Zede	dedefddZede	defddZededee	e	f ddfddZedee	e	f de
e fddZdS )_DatadogMultiHeadera  Helper class for injecting/extract Datadog multi header format

    Headers:

      - ``x-datadog-trace-id`` the context trace id as a uint64 integer
      - ``x-datadog-parent-id`` the context current span id as a uint64 integer
      - ``x-datadog-sampling-priority`` integer representing the sampling decision.
        ``<= 0`` (Reject) or ``> 1`` (Keep)
      - ``x-datadog-origin`` optional name of origin Datadog product which initiated the request
      - ``x-datadog-tags`` optional tracer tags

    Restrictions:

      - Trace tag key-value pairs in ``x-datadog-tags`` are extracted from incoming requests.
      - Only trace tags with keys prefixed with ``_dd.p.`` are propagated.
      - The trace tag keys must be printable ASCII characters excluding space, comma, and equals.
      - The trace tag values must be printable ASCII characters excluding comma. Leading and
        trailing spaces are trimmed.
    z_dd.p.upstream_servicesc                 C   s
   |  dS )Nz_dd.p.)rQ   rT   rE   rE   rF   _is_valid_datadog_trace_tag_key   r\   z3_DatadogMultiHeader._is_valid_datadog_trace_tag_keyrI   rA   c                 C   s   t t| ddS )N rJ   )rM   _POSSIBLE_HTTP_HEADER_TAGS)rI   rE   rE   rF   _get_tags_value   s
   z#_DatadogMultiHeader._get_tags_valuec                 C   st   zdd t |  D }W |S  ty$   ddi}tjd| dd Y |S  ty9   ddi}tjd| dd Y |S w )	Nc                 S   s*   i | ]\}}|t jvrt |r||qS rE   )rk   _X_DATADOG_TAGS_EXTRACT_REJECTrm   .0kvrE   rE   rF   
<dictcomp>   s    
z5_DatadogMultiHeader._extract_meta.<locals>.<dictcomp>_dd.propagation_errorextract_max_sizez#failed to decode x-datadog-tags: %rTexc_infodecoding_error)r   rO   r   logwarningr   debug)
tags_valuemetarE   rE   rF   _extract_meta   s    
z!_DatadogMultiHeader._extract_metatrace_id_hob_hexlow_64_bitsc                 C   s   t | d| dS )Nr^   rY   )rZ   r`   )r   r   rE   rE   rF   _put_together_trace_id   s   z*_DatadogMultiHeader._put_together_trace_idupper_64_bitsc                 C   sD   zt | dkst| ds|  stW dS W dS  ty!   Y dS w )NrY   FT)rS   rZ   islower
ValueError)r   rE   rE   rF   _higher_order_is_valid   s   z*_DatadogMultiHeader._higher_order_is_validspan_contextNc                 C   sr  | j d u s
| jd u rtd|  d S tjstj| jvrd S | j t	kr4t
t| j |t< t| j | jt< nt
| j |t< t
| j|t< | j}|d urPt
| j|t< | jd ur\t| j|t< tjsfd| jd< d S d| jv rmd S t| j }dd |D }|rzt|tjd|t< W n) ty   d| jd< tjdd	d
 Y n ty   d| jd< tjdd	d
 Y nw tdt  d S )N"tried to inject invalid context %rdisabledrx   c                 S   s    i | ]\}}t |r||qS rE   )rk   rm   rs   rE   rE   rF   rw     s     z/_DatadogMultiHeader._inject.<locals>.<dictcomp>)max_sizeinject_max_sizezfailed to encode x-datadog-tagsTrz   encoding_errorcontext_header_style.injected)!trace_idspan_idr}   r   
asm_config_apm_tracing_enabledr
   PROPAGATION_HEADER_metar_   strr	   r/   r   _HIGHER_ORDER_TRACE_ID_BITSr0   sampling_priorityr1   	dd_originr   r2   r   _x_datadog_tags_enabledlistrO   r   _x_datadog_tags_max_lengthr9   r   r~   r   rj   r&   )r   rI   r   context_metatags_to_encoderE   rE   rF   _inject   sF   





z_DatadogMultiHeader._injectc           	      C   s  t t| }|d u rd S zt|}W n ty   d}Y nw |dks%|tkr-td| d S t t| dd}t t| }t t	| }d }t
| }|rLt
|}|rut|v ru|t }t
|retjrdt
||}nd||d< |t= td| |syi }z4|d urt|}|rt|}tjs|rtj|vrd }n	|rtj|v rd}t|pd t|pd |||d	W S  ttfy   td
||||| Y d S w )Nr   zXInvalid trace id: %r. `x-datadog-trace-id` must be greater than zero and less than 2**640ro   zmalformed_tid {}rx   z>malformed_tid: %s. Failed to decode trace id from http headersr   r   r   r   r   r   zdreceived invalid x-datadog-* headers, trace-id: %r, parent-id: %r, priority: %r, origin: %r, tags:%r)rM   POSSIBLE_HTTP_HEADER_TRACE_IDSrZ   r   r_   r}   r~   POSSIBLE_HTTP_HEADER_PARENT_IDS(POSSIBLE_HTTP_HEADER_SAMPLING_PRIORITIESPOSSIBLE_HTTP_HEADER_ORIGINrk   rq   r   r   r   r   _128_bit_trace_id_enabledr   r`   r*   r   r   r
   r   r   	TypeErrorr   )	rI   trace_id_strr   parent_span_idr   originr   r   r   rE   rE   rF   _extract%  s   




z_DatadogMultiHeader._extract)__name__
__module____qualname____doc__rC   rr   staticmethodrm   dictr   r   rq   r   rZ   r   boolr   r   r   r   rE   rE   rE   rF   rk      s"    

 
	 ;$rk   c                   @   T   e Zd ZdZededeeef ddfddZedeeef de	e fdd	Z
dS )
_B3MultiHeadera  Helper class to inject/extract B3 Multi-Headers

    https://github.com/openzipkin/b3-propagation/blob/3e54cda11620a773d53c7f64d2ebb10d3a01794c/README.md#multiple-headers

    Example::

        X-B3-TraceId: 80f198ee56343ba864fe8b2a57d3eff7
        X-B3-ParentSpanId: 05e3ac9a4f6e3b90
        X-B3-SpanId: e457b5a2e4d86bd1
        X-B3-Sampled: 1


    Headers:

      - ``X-B3-TraceId`` header is encoded as 32 or 16 lower-hex characters.
      - ``X-B3-SpanId`` header is encoded as 16 lower-hex characters.
      - ``X-B3-Sampled`` header value of ``0`` means Deny, ``1`` means Accept, and absent means to defer.
      - ``X-B3-Flags`` header is used to set ``1`` meaning Debug or an Accept.

    Restrictions:

      - ``X-B3-Sampled`` and ``X-B3-Flags`` should never both be set

    Implementation details:

      - Sampling priority gets encoded as:
        - ``sampling_priority <= 0`` -> ``X-B3-Sampled: 0``
        - ``sampling_priority == 1`` -> ``X-B3-Sampled: 1``
        - ``sampling_priority > 1`` -> ``X-B3-Flags: 1``
      - Sampling priority gets decoded as:
        - ``X-B3-Sampled: 0`` -> ``sampling_priority = 0``
        - ``X-B3-Sampled: 1`` -> ``sampling_priority = 1``
        - ``X-B3-Flags: 1`` -> ``sampling_priority = 2``
      - ``X-B3-TraceId`` is not required, will use ``None`` when not present
      - ``X-B3-SpanId`` is not required, will use ``None`` when not present
    r   rI   rA   Nc                 C   s   | j d u s
| jd u rtd|  d S t| j |t< t| j|t< | j}|d urA|dkr0d|t< n|dkr9d|t< n|dkrAd|t	< t
dt d S )Nr   r   r   r,   1r   )r   r   r}   r   ra   r5   r6   r   r7   r8   rj   r$   )r   rI   r   rE   rE   rF   r     s   

z_B3MultiHeader._injectc              
   C   s   t t| }|d u rd S t t| }t t| }t t| }z9d }d }|d ur)t|p(d }|d ur3t|p2d }d }|d urF|dkr@t}n|dkrFt}|dkrLt}t	|||dW S  t
tfyh   td|||| Y d S w )Nr   r   r   r   r   zRreceived invalid x-b3-* headers, trace-id: %r, span-id: %r, sampled: %r, flags: %r)rM   "_POSSIBLE_HTTP_HEADER_B3_TRACE_IDS!_POSSIBLE_HTTP_HEADER_B3_SPAN_IDS!_POSSIBLE_HTTP_HEADER_B3_SAMPLEDS_POSSIBLE_HTTP_HEADER_B3_FLAGS_b3_id_to_dd_idr   r   r   r   r   r   r}   r   )rI   trace_id_valspan_id_valsampledflagsr   r   r   rE   rE   rF   r     s`   z_B3MultiHeader._extractr   r   r   r   r   r   r   r   r   r   r   rE   rE   rE   rF   r     s    % $r   c                   @   r   )
_B3SingleHeadera9  Helper class to inject/extract B3

    https://github.com/openzipkin/b3-propagation/blob/3e54cda11620a773d53c7f64d2ebb10d3a01794c/README.md#single-header

    Format::

        b3={TraceId}-{SpanId}-{SamplingState}-{ParentSpanId}

    Example::

        b3: 80f198ee56343ba864fe8b2a57d3eff7-e457b5a2e4d86bd1-1-05e3ac9a4f6e3b90


    Values:

      - ``TraceId`` header is encoded as 32 or 16 lower-hex characters.
      - ``SpanId`` header is encoded as 16 lower-hex characters.
      - ``SamplingState`` header value of ``0`` means Deny, ``1`` means Accept, and ``d`` means Debug
      - ``ParentSpanId`` header is not used/ignored if sent

    Restrictions:

      - ``ParentSpanId`` value is ignored/not used

    Implementation details:

      - Sampling priority gets encoded as:
        - ``sampling_priority <= 0`` -> ``SamplingState: 0``
        - ``sampling_priority == 1`` -> ``SamplingState: 1``
        - ``sampling_priority > 1`` -> ``SamplingState: d``
      - Sampling priority gets decoded as:
        - ``SamplingState: 0`` -> ``sampling_priority = 0``
        - ``SamplingState: 1`` -> ``sampling_priority = 1``
        - ``SamplingState: d`` -> ``sampling_priority = 2``
      - ``TraceId`` is not required, will use ``None`` when not present
      - ``SpanId`` is not required, will use ``None`` when not present
    r   rI   rA   Nc                 C   s   | j d u s
| jd u rtd|  d S dt| j t| j}| j}|d ur?|dkr.|d7 }n|dkr7|d7 }n|dkr?|d7 }||t< tdt	 d S )	Nr   z{}-{}r   z-0r,   z-1z-dr   )
r   r   r}   r   r`   ra   r   r4   rj   r%   )r   rI   single_headerr   rE   rE   rF   r     s   

z_B3SingleHeader._injectc           	   	   C   s
  t t| }|s	d S d }d }d }|d}d }d }t|dkr"|\}nt|dkr-|\}}nt|dkr<|d d \}}}z6|d urGt|pFd }|d urQt|pPd }d }|d urk|dkr^t}n|dkret}n|dkrkt}t|||dW S  t	t
fy   td	| Y d S w )
N-r,   r      r   r   dr   z"received invalid b3 header, b3: %r)rM   &_POSSIBLE_HTTP_HEADER_B3_SINGLE_HEADERsplitrS   r   r   r   r   r   r   r   r}   r   )	rI   r   r   r   r   partsr   r   r   rE   rE   rF   r   1  sP   


z_B3SingleHeader._extractr   rE   rE   rE   rF   r     s    & $r   c                   @   s&  e Zd ZdZedd Zededeeee	d f fddZ
ed	ee deee eeef ee ee f fd
dZe	ddedee dee fddZedeeef dee fddZe	ddededee	d  dee deeeef  defddZededeeef ddfddZdS ) _TraceContexta	  Helper class to inject/extract W3C Trace Context
    https://www.w3.org/TR/trace-context/
    Overview:
      - ``traceparent`` header describes the position of the incoming request in its
        trace graph in a portable, fixed-length format. Its design focuses on
        fast parsing. Every tracing tool MUST properly set traceparent even when
        it only relies on vendor-specific information in tracestate
      - ``tracestate`` header extends traceparent with vendor-specific data represented
        by a set of name/value pairs. Storing information in tracestate is
        optional.

    The format for ``traceparent`` is::
      HEXDIGLC        = DIGIT / "a" / "b" / "c" / "d" / "e" / "f"
      value           = version "-" version-format
      version         = 2HEXDIGLC
      version-format  = trace-id "-" parent-id "-" trace-flags
      trace-id        = 32HEXDIGLC
      parent-id       = 16HEXDIGLC
      trace-flags     = 2HEXDIGLC

    Example value of HTTP ``traceparent`` header::
        value = 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
        base16(version) = 00
        base16(trace-id) = 4bf92f3577b34da6a3ce929d0e0e4736
        base16(parent-id) = 00f067aa0ba902b7
        base16(trace-flags) = 01  // sampled

    The format for ``tracestate`` is key value pairs with each entry limited to 256 characters.
    An example of the ``dd`` list member we would add is::
    "dd=s:2;o:rum;t.dm:-4;t.usr.id:baz64;t.ksr:0.0001"

    Implementation details:
      - Datadog Trace and Span IDs are 64-bit unsigned integers.
      - The W3C Trace Context Trace ID is a 16-byte hexadecimal string.
      - If the incoming traceparent is invalid we DO NOT use the tracecontext headers.
        Otherwise, the trace-id value is set to the hex-encoded value of the trace-id.
        If the trace-id is a 64-bit value (i.e. a Datadog trace-id),
        then the upper half of the hex-encoded value will be all zeroes.

      - The tracestate header will have one list member added to it, ``dd``, which contains
        values that would be in x-datadog-tags as well as those needed for propagation information.
        The keys to the ``dd`` values have been shortened as follows to save space:
        ``sampling_priority`` = ``s``
        ``origin`` = ``o``
        ``_dd.p.`` prefix = ``t.``
    c                 C   s   |  ddS )N~=)replace)tag_valrE   rE   rF   decode_tag_val  s   z_TraceContext.decode_tag_valtprA   )r   r,   c                 C   s   t |  }|du rtd|  | \}}}}}|dkr$td|  |dkr/td| n|dkr=|dur=td|  t|}t|}|dkrMtd	|dkrUtd
t|}	|	d@ r_dnd}
|||
fS )zIf there is no traceparent, or if the traceparent value is invalid raise a ValueError.
        Otherwise we extract the trace-id, span-id, and sampling priority from the
        traceparent header.
        NzInvalid traceparent version: %sffz(ff is an invalid traceparent version: %s00z=unsupported traceparent version:%r, still attempting to parsezRTraceparents with the version `00` should contain 4 values delimited by a dash: %sr   z0 value for trace_id is invalidz0 value for span_id is invalidr,   )_TRACEPARENT_HEX_REGEXmatchstripr   groupsr}   r~   r[   )r   valid_tp_valuesversiontrace_id_hexspan_id_hextrace_flags_hexfuture_valsr   r   trace_flagsr   rE   rE   rF   _get_traceparent_values  s2   
z%_TraceContext._get_traceparent_valuests_lc                 C   s   d }| D ]}| dr|dd  }tdd |dD }q|rP|d}|d ur.t|}nd }|d}|r<t|}|d}d	d
 | D }||||fS d i d d fS )Nzdd=r   c                 s   s    | ]	}| d dV  qdS ):r,   N)r   )rt   itemrE   rE   rF   	<genexpr>  s    z7_TraceContext._get_tracestate_values.<locals>.<genexpr>;sopc                 S   s2   i | ]\}}| d rd|dd  t|qS )zt.z_dd.p.%sr   N)rQ   r   r   rs   rE   rE   rF   rw     s
    z8_TraceContext._get_tracestate_values.<locals>.<dictcomp>)rQ   r   r   getrZ   r   r   rO   )r   ddlist_memsampling_priority_tssampling_priority_ts_intr   lpidother_propagated_tagsrE   rE   rF   _get_tracestate_values  s(   





z$_TraceContext._get_tracestate_valuesNtraceparent_sampledtracestate_sampling_priorityr   c                 C   sV   | o|dk}|s| dkr|r|dkrd}|S |s'| dkr'|r#|dk r'd}|S |}|S )a  
        When the traceparent sampled flag is set, the Datadog sampling priority is either
        1 or a positive value of sampling priority if propagated in tracestate.

        When the traceparent sampled flag is not set, the Datadog sampling priority is either
        0 or a negative value of sampling priority if propagated in tracestate.

        When origin is "rum" and there is no sampling priority propagated in tracestate, the above rules do not apply.
        rumr   r,   rE   )r   r   r   from_rum_wo_priorityr   rE   rE   rF   _get_sampling_priority  s&   z$_TraceContext._get_sampling_priorityrI   c              	   C   s   zt t| }|d u rtd W d S t|\}}}W n ttfy1   tjd|ddid Y d S w t	|i}t t
| }t|||||S )Nzno traceparent headerz%received invalid w3c traceparent: %s send_to_telemetryF)extra)rM   !_POSSIBLE_HTTP_HEADER_TRACEPARENTr}   r   r   r   r   AssertionError	exceptionr'    _POSSIBLE_HTTP_HEADER_TRACESTATE_get_context)rI   r   r   r   
trace_flagr   tsrE   rE   rF   r     s   


z_TraceContext._extractr   r   r   r   r   c              	   C   s   |d u ri }d }|}|rndd | dD }d|}td|r(td| nF||t< zt|}W n t	t
fyF   td| d }Y nw |rh|\}	}
}}||
  |r\||t< |d urgt||	|}ntd| t| ||||dS )	Nc                 S   s   g | ]}|  qS rE   r   )rt   memberrE   rE   rF   
<listcomp>5  s    z._TraceContext._get_context.<locals>.<listcomp>,z[^\x20-\x7E]+z&received invalid tracestate header: %rz3received invalid dd header value in tracestate: %r z9no dd list member in tracestate from incoming request: %rr   )r   joinresearchr}   r   r(   r   r   r   r   updaterO   r"   r   r   )r   r   r   r   r   r   r   r   tracestate_valuesr   r   r   rE   rE   rF   r   &  sD   
z_TraceContext._get_contextr   c                 C   sx   | j }|r5||t< | jdu rt| j| jpd|t< nt| jv r0t	| jt d}t| j||t< n| j|t< t
dt d S )NFr   rY   r   )_traceparentr;   
_is_remoter+   _tracestater   r=   r"   r   rZ   rj   r   )r   rI   r   r   rE   rE   rF   r   Y  s   



z_TraceContext._injectrB   )r   r   r   r   r   r   r   tuplerZ   r   r   r   r   r   r   r   r   r   r   r   rE   rE   rE   rF   r   j  sH    /
",8%" 
2$r   c                   @   s   e Zd ZdZdZdZededefddZededefd	d
Z	ede
deeef ddfddZede
fddZedeeef de
fddZdS )_BaggageHeaderz.Helper class to inject/extract Baggage HeaderszMABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&'*+-.^_`|~zYABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&'()*+-./:<>?@[]^_`{|}~rT   rA   c                 C      t jjt|  tjdS N)safe)urllibparsequoter   r   r
  SAFE_CHARACTERS_KEYrl   rE   rE   rF   _encode_keyt     z_BaggageHeader._encode_keyrU   c                 C   r  r  )r  r  r  r   r   r
  SAFE_CHARACTERS_VALUE)rU   rE   rE   rF   _encode_valuex  r  z_BaggageHeader._encode_valuer   rI   Nc           
      C   s  | j  }|s	d S zqt|tkr%td tjtj	dddd t
|t}g }d}|D ]>\}}t| dt| }t|d|rFdnd }|| tkr`td	 tjtj	ddd
d  n
|| ||7 }q+d|}	|	|t< tdt W d S  ty   td Y d S w )Nz2Baggage item limit exceeded, dropping excess itemszcontext_header.truncatedr,   ))truncation_reasonbaggage_item_count_exceededrd   r   r   zutf-8z3Baggage header size exceeded, dropping excess items))r  baggage_byte_count_exceededr   r   z*Failed to encode and inject baggage header)_baggagerO   rS   r    r}   r~   r   rh   r   ri   	itertoolsislicer
  r  r  encoder   appendr  r?   rj   r   	Exception)
r   rI   baggage_itemsencoded_items
total_sizerT   rU   r   	item_sizeheader_valuerE   rE   rF   r   |  sF   





z_BaggageHeader._injectc                   C   s$   t jtjdddtffd ti dS )zGRecord telemetry for malformed baggage header and return empty context.zcontext_header_style.malformedr,   rc   rd   r>   )r   rh   r   ri   r   r   rE   rE   rE   rF   "_record_malformed_and_return_empty  s   
z1_BaggageHeader._record_malformed_and_return_emptyc                 C   s   t t| }|sti dS i }|d}|D ]2}d|vr!t   S |dd\}}tj|	 }tj|	 }|r=|sCt   S |||< qt|dS )Nr$  r   r   r,   )
rM   _POSSIBLE_HTTP_BAGGAGE_HEADERr   r   r
  r%  r  r  unquoter   )rI   r#  r>   baggages	key_valuerT   rU   rE   rE   rF   r     s   




z_BaggageHeader._extract)r   r   r   r   r  r  r   r   r  r  r   r   r   r%  r   rE   rE   rE   rF   r
  n  s     ,
 r
  c                
   @   s   e Zd ZdZe	ddeeef dee defddZ	ede
eef deee ee f fd	d
Zededededee fddZedd Zedeeef de
eef ddfddZedd ZdS )HTTPPropagatorzA HTTP Propagator using HTTP headers as carrier. Injects and Extracts headers
    according to the propagation style set by ddtrace configurations.
    N
trace_infonon_active_spanrA   c                 C   s   t | tr| jn| }|jdur|S tjdu rtd| |S d}|dur(|j}nt | tr1| j}ntj	  }r@|j
| j
kr@|}|rOtj| td|| |S )zHandle sampling decision and return context for header injection.

        If sampling_priority is already set, returns immediately. Otherwise, finds the
        appropriate span and triggers sampling before returning the injection context.
        NzTNo tracer found and injection context %s has no sampling priority, skipping samplingz4%s sampled before propagating trace: span_context=%s)
isinstancer   rN   r   r   tracerr}   error_local_rootcurrent_root_spanr   sampler   )r+  r,  injection_contextsampling_spancurrent_rootrE   rE   rF   _get_sampled_injection_context  s(   



z-HTTPPropagator._get_sampled_injection_contextnormalized_headersc                 C   sd   g }g }t jd ur.t jD ]!}|tkrqt| }|| }|r-td| || || q||fS )Ncontext_header_style.extracted)r   _propagation_style_extractr   _PROP_STYLESr   rj   r  )r7  contextsstyles_w_ctx
prop_style
propagatorrN   rE   rE   rF   "_extract_configured_contexts_avail  s   





z1HTTPPropagator._extract_configured_contexts_availrN   stylereasonc                 C   sV   | j r)| jr)t| j| j | jr| jdkrdnd|tkr!| jtdnd ||ddS d S )Nr   r,   rn   )rA  context_headers)r   r<   
attributes)r   r   r   r   r   r   r   r(   )rN   r@  rA  rE   rE   rF   _context_to_span_link  s   z$HTTPPropagator._context_to_span_linkc                 C   s   | d }g }t | dd  dD ]f\}}|| }|jr/|j|jkr/t||d}|r.|| q|tkrutt|}	|	r?|	|jt	< |j|jkru|j
|j
krud }
t|v rX| |t }
t|jv rf|jt |jt< n|
rqd|
j
|jt< |j
|_
q||_|S )Nr   r,   terminated_contextr^   )	enumerater   r*  rD  r  r   rM   r   r   r(   r   r&   indexr"   r`   _span_links)r;  r<  r7  primary_contextlinksirN   style_w_ctxlinkr   
dd_contextrE   rE   rF   _resolve_contexts$  s:   



z HTTPPropagator._resolve_contextsrI   c                 C   s  t | d}|jr|jr|jdu rtd| | td||f t	j
s%dS tt	j
v r0t|| |jdu s:|jdu rBtd| dS t	jdu r[|jdur[|jD ]}|j| |t| < qOtt	j
v rft|| tt	j
v rqt|| tt	j
v r|t|| tt	j
v rt|| dS dS )a(  Inject Context attributes that have to be propagated as HTTP headers.

        Here is an example using `requests`::

            import requests

            from ddtrace.propagation.http import HTTPPropagator

            def parent_call():
                with tracer.start_span('parent_span') as span:
                    headers = {}
                    # Preferred: Pass span object to context argument
                    HTTPPropagator.inject(span, headers)
                    url = '<some RPC endpoint>'
                    r = requests.get(url, headers=headers)

                with tracer.start_span('child_span2') as span:
                    headers = {}
                    # Alternative: Pass context, but ensure sampling_priority is set
                    tracer.sample(span)
                    HTTPPropagator.inject(span.context, headers)
                    url = '<some RPC endpoint>'
                    r = requests.get(url, headers=headers)

        :param Union[Span, Context] context: Pass a Span object (preferred) or Context object.
            Span objects automatically trigger sampling decisions. Context objects should have
            sampling_priority set to avoid inconsistent downstream sampling.
        :param dict headers: HTTP headers to extend with tracing attributes.
        NzSampling decision not available. Downstream spans will not inherit a sampling priority: args=(context=%s, ...) detected span context=%szhttp.span_injectr   T)r*  r6  r   r   r   r}   r   r   dispatchr   _propagation_style_injectr   r
  r   !_propagation_http_baggage_enabledr  r.   r&   rk   r$   r   r%   r   r   r   )rN   rI   r   rT   rE   rE   rF   injectK  s6   !





zHTTPPropagator.injectc                 C   s  t  }| rtjs
|S zd}dd |  D }tjr<tjD ]}t| }||}|}|r0td| tjdu r:t	||  n t
|\}}|rI|d }|r\t
|||}tjdu r\t	|| ttjv rt|}|ji krtdt |rx| |_n|}tjrdd tjD }	d	|	v r|  }
n|	}
|
D ]}|| }d
urt| }||jvr||j|< qtjtkrt
||d}t | |r|gng d}|W S  ty   tjddd Y t  S w )a  Extract a Context from HTTP headers into a new Context.
        For tracecontext propagation we extract tracestate headers for
        propagation even if another propagation style is specified before tracecontext,
        so as to always propagate other vendor's tracestate values by default.
        This is skipped if the tracer is configured to take the first style it matches.

        Here is an example from a web endpoint::

            from ddtrace.propagation.http import HTTPPropagator

            def my_controller(url, headers):
                context = HTTPPropagator.extract(headers)
                if context:
                    tracer.context_provider.activate(context)

                with tracer.trace('my_controller') as span:
                    span.set_tag('http.url', url)

        :param dict headers: HTTP headers to extract tracing attributes.
        :return: New `Context` with propagated attributes.
        rn   c                 S   s   i | ]	\}}|  |qS rE   )rD   )rt   rf   rv   rE   rE   rF   rw     s    z*HTTPPropagator.extract.<locals>.<dictcomp>r8  Tr   c                 S   s   g | ]
}|  r|  qS rE   r   )rt   ru   rE   rE   rF   r     s    z*HTTPPropagator.extract.<locals>.<listcomp>*Npropagation_behavior_extract)r>   
span_linksz2error while extracting context propagation headersrz   )r   r   r9  rO   _propagation_extract_firstr:  r   rj   rR  rW   r*  r?  rO  r   r
  r  get_all_baggage_items_baggage_tag_keyskeysget_baggage_itemr   r   _propagation_behavior_extractr   rD  r  r}   r   )rI   rN   r@  r7  r=  r>  r;  r<  baggage_contextraw_keystag_keysstripped_keyrU   prefixed_keyrM  rE   rE   rF   extract  sd   














zHTTPPropagator.extractrB   )r   r   r   r   r   r   r   r   r   r6  r   r   r	  r   r?  r   rD  rO  rS  rb  rE   rE   rE   rF   r*    s*    
(, 
&(Dr*  rB   )xr  r  typingr   r   r   urllib.parser  ddtrace._trace._span_linkr   ddtrace._trace.contextr   ddtrace._trace.spanr   r   r	   ddtrace.appsec._constantsr
   ddtrace.internalr   !ddtrace.internal.settings._configr   ddtrace.internal.settings.asmr   ddtrace.internal.telemetryr   $ddtrace.internal.telemetry.constantsr   	constantsr   r   r   internal._tagsetr   r   r   r   r   r   internal.compatr   internal.constantsr   r   r   r   r   r    r!   r   r"   r#   r_   r$   r%   r&   r'   r(   internal.loggerr)   internal.samplingr*   internal.utils.httpr+   _utilsr-   r   r}   r.   __annotations__r/   r0   r1   r2   r4   r5   r6   r7   r8   r9   r;   r=   r?   r   rC   rG   r   r   r   r   rD   rp   r   r   r   r   r   r   r   rP   r&  compileVERBOSEr   r   rM   rW   rZ   r[   r   ra   rj   rk   r   r   r   r
  r:  objectr*  rE   rE   rE   rF   <module>   s   
 	


	 cut  ]	