@@ -204,6 +204,28 @@ pub(crate) fn uses_legacy_lifecycle(
204204 && protocol_version. is_none_or ( |version| version < & ProtocolVersion :: V_2026_07_28 )
205205}
206206
207+ /// Translate the transport-attached [`InboundStreamOrigin`] marker (if any)
208+ /// and the in-flight outbound request pool into the association passed to
209+ /// [`ServiceRole::enforce_peer_request_association`].
210+ pub ( crate ) fn peer_request_association < Req : crate :: model:: GetExtensions , V > (
211+ request : & Req ,
212+ local_responder_pool : & std:: collections:: HashMap < RequestId , V > ,
213+ ) -> PeerRequestAssociation {
214+ match request. extensions ( ) . get :: < InboundStreamOrigin > ( ) {
215+ None => PeerRequestAssociation :: Unknown {
216+ has_pending_outbound_request : !local_responder_pool. is_empty ( ) ,
217+ } ,
218+ Some ( InboundStreamOrigin :: Unassociated ) => PeerRequestAssociation :: Unassociated ,
219+ Some ( InboundStreamOrigin :: OutboundRequest ( id) ) => {
220+ if local_responder_pool. contains_key ( id) {
221+ PeerRequestAssociation :: Associated
222+ } else {
223+ PeerRequestAssociation :: Unassociated
224+ }
225+ }
226+ }
227+ }
228+
207229tokio:: task_local! {
208230 pub ( crate ) static ORIGINATING_REQUEST : RequestId ;
209231}
@@ -1487,9 +1509,7 @@ where
14871509 if let Err ( error) = R :: enforce_peer_request_association (
14881510 & request,
14891511 peer. peer_info ( ) . as_deref ( ) ,
1490- PeerRequestAssociation :: Unknown {
1491- has_pending_outbound_request : !local_responder_pool. is_empty ( ) ,
1492- } ,
1512+ peer_request_association ( & request, & local_responder_pool) ,
14931513 ) {
14941514 tracing:: warn!( %id, message = %error. message, "rejected peer request" ) ;
14951515 // send directly: the sink proxy path would drop the
@@ -1770,4 +1790,73 @@ mod sep2260_marker_tests {
17701790 let request = send_and_capture ( None ) . await ;
17711791 assert ! ( request. extensions( ) . get:: <OriginatingRequestId >( ) . is_none( ) ) ;
17721792 }
1793+
1794+ #[ test]
1795+ #[ expect(
1796+ deprecated,
1797+ reason = "Sampling is deprecated by SEP-2577 but remains the canonical restricted request"
1798+ ) ]
1799+ fn peer_request_association_maps_stream_origin ( ) {
1800+ use std:: collections:: HashMap ;
1801+
1802+ use crate :: model:: {
1803+ CreateMessageRequest , CreateMessageRequestParams , SamplingMessage , ServerRequest ,
1804+ } ;
1805+
1806+ fn sampling ( origin : Option < InboundStreamOrigin > ) -> ServerRequest {
1807+ let mut request = CreateMessageRequest :: new ( CreateMessageRequestParams :: new (
1808+ vec ! [ SamplingMessage :: user_text( "hi" ) ] ,
1809+ 16 ,
1810+ ) ) ;
1811+ if let Some ( origin) = origin {
1812+ request. extensions . insert ( origin) ;
1813+ }
1814+ ServerRequest :: CreateMessageRequest ( request)
1815+ }
1816+
1817+ let empty: HashMap < RequestId , ( ) > = HashMap :: new ( ) ;
1818+ let in_flight: HashMap < RequestId , ( ) > = HashMap :: from ( [ ( RequestId :: Number ( 7 ) , ( ) ) ] ) ;
1819+
1820+ // No marker (stdio): coarse signal.
1821+ assert_eq ! (
1822+ peer_request_association( & sampling( None ) , & in_flight) ,
1823+ PeerRequestAssociation :: Unknown {
1824+ has_pending_outbound_request: true
1825+ }
1826+ ) ;
1827+ assert_eq ! (
1828+ peer_request_association( & sampling( None ) , & empty) ,
1829+ PeerRequestAssociation :: Unknown {
1830+ has_pending_outbound_request: false
1831+ }
1832+ ) ;
1833+ // Standalone GET stream: unassociated even with requests in flight.
1834+ assert_eq ! (
1835+ peer_request_association(
1836+ & sampling( Some ( InboundStreamOrigin :: Unassociated ) ) ,
1837+ & in_flight
1838+ ) ,
1839+ PeerRequestAssociation :: Unassociated
1840+ ) ;
1841+ // Originating POST stream of an in-flight request: associated.
1842+ assert_eq ! (
1843+ peer_request_association(
1844+ & sampling( Some ( InboundStreamOrigin :: OutboundRequest (
1845+ RequestId :: Number ( 7 )
1846+ ) ) ) ,
1847+ & in_flight
1848+ ) ,
1849+ PeerRequestAssociation :: Associated
1850+ ) ;
1851+ // Stream of a request that is no longer in flight: unassociated.
1852+ assert_eq ! (
1853+ peer_request_association(
1854+ & sampling( Some ( InboundStreamOrigin :: OutboundRequest (
1855+ RequestId :: Number ( 8 )
1856+ ) ) ) ,
1857+ & in_flight
1858+ ) ,
1859+ PeerRequestAssociation :: Unassociated
1860+ ) ;
1861+ }
17731862}
0 commit comments