7676SSEEvent = dict [str , Any ]
7777
7878
79+ def _parse_accept_header (accept_header : str ) -> list [str ]:
80+ """Parse the Accept header into a list of acceptable media types, honoring q=0 values."""
81+ media_types : list [str ] = []
82+ for entry in accept_header .split ("," ):
83+ parts = [part .strip () for part in entry .split (";" ) if part .strip ()]
84+ if not parts :
85+ continue
86+
87+ media_type = parts [0 ].lower ()
88+ q = 1.0
89+ for param in parts [1 :]:
90+ param = param .strip ()
91+ if param .startswith ("q=" ):
92+ try :
93+ q = float (param [2 :])
94+ except ValueError :
95+ q = 1.0
96+ break
97+
98+ if q <= 0 :
99+ continue
100+
101+ media_types .append (media_type )
102+ return media_types
103+
104+
79105def check_accept_headers (request : Request ) -> tuple [bool , bool ]:
80106 """Return (has_json, has_sse) for the request's Accept header, with RFC 7231 wildcard handling.
81107
@@ -85,7 +111,7 @@ def check_accept_headers(request: Request) -> tuple[bool, bool]:
85111 - text/* matches any text/ subtype
86112 """
87113 accept_header = request .headers .get ("accept" , "" )
88- accept_types = [ media_type . strip (). split ( ";" )[ 0 ]. strip (). lower () for media_type in accept_header . split ( "," )]
114+ accept_types = _parse_accept_header ( accept_header )
89115
90116 has_wildcard = "*/*" in accept_types
91117 has_json = has_wildcard or any (t in (CONTENT_TYPE_JSON , "application/*" ) for t in accept_types )
@@ -436,9 +462,14 @@ async def handle_request(self, scope: Scope, receive: Receive, send: Send) -> No
436462 def _check_content_type (self , request : Request ) -> bool :
437463 """Check if the request has the correct Content-Type."""
438464 content_type = request .headers .get ("content-type" , "" )
439- content_type_parts = [part .strip () for part in content_type .split (";" )[0 ].split ("," )]
440465
441- return any (part == CONTENT_TYPE_JSON for part in content_type_parts )
466+ # Only normalize the media type (drop parameters) and compare
467+ media_types = [
468+ part .strip ().lower ()
469+ for part in content_type .split (";" , 1 )[0 ].split ("," )
470+ ]
471+
472+ return CONTENT_TYPE_JSON in media_types
442473
443474 async def _validate_accept_header (self , request : Request , scope : Scope , send : Send ) -> bool :
444475 """Validate Accept header based on response mode. Returns True if valid."""
0 commit comments