@@ -540,73 +540,75 @@ async def _parse_multipart_part(
540540 :param part: aiohttp BodyPartReader for the part
541541 :return: ExecutionResult or None if part is empty/heartbeat
542542 """
543- # Verify the part has the correct content type
543+ try :
544+ body = await part .text ()
545+ body = body .strip ()
546+ except UnicodeDecodeError as e :
547+ log .warning (f"Failed to decode part: { ascii (e )} " )
548+ return None
549+
544550 content_type = part .headers .get (aiohttp .hdrs .CONTENT_TYPE , "" )
545- if not content_type :
546- log .debug ("Skipping part with no content-type (likely heartbeat)" )
551+
552+ if not content_type and not body :
553+ log .debug ("Skipping part with no content-type and no body" )
547554 return None
555+
556+ # Verify the part has the correct content type
548557 if not content_type .startswith ("application/json" ):
549558 raise TransportProtocolError (
550559 f"Unexpected part content-type: { content_type } . "
551560 "Expected 'application/json'."
552561 )
553562
554- try :
555- # Read the part content as text
556- body = await part .text ()
557- body = body .strip ()
558-
559- if log .isEnabledFor (logging .DEBUG ):
560- log .debug ("<<< %s" , ascii (body or "(empty body, skipping)" ))
563+ if log .isEnabledFor (logging .DEBUG ):
564+ log .debug ("<<< %s" , ascii (body or "(empty body, skipping)" ))
561565
562- if not body :
563- return None
566+ if not body :
567+ return None
564568
565- # Parse JSON body using custom deserializer
569+ try :
566570 data = self .json_deserialize (body )
567-
568- # Handle heartbeats - empty JSON objects
569- if not data :
570- log .debug ("Received heartbeat, ignoring" )
571- return None
572-
573- # The multipart subscription protocol wraps data in a "payload" property
574- if "payload" not in data :
575- log .warning ("Invalid response: missing 'payload' field" )
576- return None
577-
578- payload = data ["payload" ]
579-
580- # Check for transport-level errors (payload is null)
581- if payload is None :
582- # If there are errors, this is a transport-level error
583- errors = data .get ("errors" )
584- if errors :
585- error_messages = [
586- error .get ("message" , "Unknown transport error" )
587- for error in errors
588- ]
589-
590- for message in error_messages :
591- log .error (f"Transport error: { message } " )
592-
593- raise TransportServerError ("\n \n " .join (error_messages ))
594- else :
595- # Null payload without errors - just skip this part
596- return None
597-
598- # Extract GraphQL data from payload
599- return ExecutionResult (
600- data = payload .get ("data" ),
601- errors = payload .get ("errors" ),
602- extensions = payload .get ("extensions" ),
603- )
604571 except json .JSONDecodeError as e :
605572 log .warning (
606573 f"Failed to parse JSON: { ascii (e )} , "
607574 f"body: { ascii (body [:100 ]) if body else '' } "
608575 )
609576 return None
610- except UnicodeDecodeError as e :
611- log .warning (f"Failed to decode part: { ascii (e )} " )
577+
578+ # Handle heartbeats - empty JSON objects
579+ if not data :
580+ log .debug ("Received heartbeat, ignoring" )
581+ return None
582+
583+ # The multipart subscription protocol wraps data in a "payload" property
584+ if "payload" not in data :
585+ log .warning ("Invalid response: missing 'payload' field" )
612586 return None
587+
588+ payload = data ["payload" ]
589+
590+ # Check for transport-level errors (payload is null)
591+ if payload is None :
592+ # If there are errors, this is a transport-level error
593+ errors = data .get ("errors" )
594+ if errors :
595+ error_messages = [
596+ error .get ("message" , "Unknown transport error" )
597+ for error in errors
598+ ]
599+
600+ for message in error_messages :
601+ log .error (f"Transport error: { message } " )
602+
603+ raise TransportServerError ("\n \n " .join (error_messages ))
604+ else :
605+ # Null payload without errors - just skip this part
606+ return None
607+
608+ # Extract GraphQL data from payload
609+ return ExecutionResult (
610+ data = payload .get ("data" ),
611+ errors = payload .get ("errors" ),
612+ extensions = payload .get ("extensions" ),
613+ )
614+
0 commit comments