@@ -485,11 +485,15 @@ def _confirmRead(page, pattern, baseline):
485485 return None
486486
487487
488- def _normalizeEscaping (text ):
489- """Bounded, non-resolving decode of the common reflection encodings (HTML entities, percent-
490- encoding, JS \\ uXXXX / escaped slash) so an ESCAPED entity reference (&e;, &e;, &e;,
491- %26e%3B, \\ u0026e;) is unmasked and can be recognised as reflection rather than file content."""
488+ def _reflectsEntity (text , ent ):
489+ """True if the random entity NAME surfaces at ANY bounded de-escaping depth (raw included) - i.e.
490+ the parser echoed the reference in some encoding (&e;, &e;, &e;, %26e%3B, \\ u0026e;)
491+ rather than expanding the external entity, so it is reflection, not file content. Checked at every
492+ step because a further round of htmlUnescape can consume an entity-name prefix that is itself a
493+ valid HTML entity (e.g. 'lt...'/'gt...'/'amp...'), which would otherwise mask the reflection."""
492494 out = getUnicode (text )
495+ if ent in out :
496+ return True
493497 for _ in range (3 ): # a few rounds catch double-encoding; capped
494498 prev = out
495499 try :
@@ -501,9 +505,11 @@ def _normalizeEscaping(text):
501505 except Exception :
502506 pass
503507 out = out .replace ("\\ u0026" , "&" ).replace ("\\ u003b" , ";" ).replace ("\\ /" , "/" )
508+ if ent in out :
509+ return True
504510 if out == prev :
505511 break
506- return out
512+ return False
507513
508514
509515def _readBetweenMarkers (xml , rootName , systemId , isB64 , m1 , m2 ):
@@ -521,14 +527,14 @@ def _readBetweenMarkers(xml, rootName, systemId, isB64, m1, m2):
521527 data = match .group (1 )
522528 # a reflected (not expanded) entity in ANY encoding: the random entity NAME survives de-escaping ->
523529 # the parser echoed the reference, it did not resolve the external entity -> not file content
524- if not data .strip () or ent in _normalizeEscaping (data ):
530+ if not data .strip () or _reflectsEntity (data , ent ):
525531 return None , payload
526532 if isB64 :
527533 try :
528534 data = getText (decodeBase64 (data .strip ())) # strict base64 also validates real bytes
529535 except Exception :
530536 return None , payload
531- if not data or not data .strip () or ent in _normalizeEscaping (data ):
537+ if not data or not data .strip () or _reflectsEntity (data , ent ):
532538 return None , payload
533539 return (data if (data and data .strip ()) else None ), payload
534540
0 commit comments