{"record":{"id":"87e6c95ca70beed0","repo":"apache/hadoop","slug":"bad-html-quoting-for","errorCode":null,"errorMessage":"Bad HTML quoting for {}","messagePattern":"Bad HTML quoting for (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HtmlQuoting.java","lineNumber":205,"sourceCode":"        next += 5;\n      } else if (item.startsWith(\"&apos;\", next)) {\n        buffer.append('\\'');\n        next += 6;        \n      } else if (item.startsWith(\"&gt;\", next)) {\n        buffer.append('>');\n        next += 4;\n      } else if (item.startsWith(\"&lt;\", next)) {\n        buffer.append('<');\n        next += 4;\n      } else if (item.startsWith(\"&quot;\", next)) {\n        buffer.append('\"');\n        next += 6;\n      } else {\n        int end = item.indexOf(';', next)+1;\n        if (end == 0) {\n          end = len;\n        }\n        throw new IllegalArgumentException(\"Bad HTML quoting for \" + \n                                           item.substring(next,end));\n      }\n      posn = next;\n      next = item.indexOf('&', posn);\n    }\n    buffer.append(item.substring(posn, len));\n    return buffer.toString();\n  }\n  \n  public static void main(String[] args) throws Exception {\n    for(String arg:args) {\n      System.out.println(\"Original: \" + arg);\n      String quoted = quoteHtmlChars(arg);\n      System.out.println(\"Quoted: \"+ quoted);\n      String unquoted = unquoteHtmlChars(quoted);\n      System.out.println(\"Unquoted: \" + unquoted);\n      System.out.println();\n    }","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HtmlQuoting.java#L187-L223","documentation":"HtmlQuoting.unquoteHtmlChars(String) is the inverse of quoteHtmlChars and only understands the five entities written by this class: &amp; &apos; &gt; &lt; &quot;. Any other '&...' sequence (for example &nbsp;, &#39;, or stray text after an ampersand ending in ';') throws IllegalArgumentException naming the offending entity. The class is used by Hadoop's web UI code to round-trip strings it escaped itself; it is not a general-purpose HTML entity decoder.","triggerScenarios":"Calling HtmlQuoting.unquoteHtmlChars on input escaped by a different encoder (numeric character references like &#39; are the classic case, since this parser has no '&#' branch); parsing web UI strings that contain named entities Hadoop never emits.","commonSituations":"Custom tooling that reuses HtmlQuoting to decode form parameters or log lines containing browser-escaped text; feed pipelines that pass arbitrary HTML through Hadoop web helpers.","solutions":["Only unquote strings that were produced by HtmlQuoting.quoteHtmlChars (or that contain no '&')","Convert numeric references first (e.g. replace('&#39;', \"'\")) or decode with a full HTML unescaper before calling unquoteHtmlChars","Wrap the call in try-catch IllegalArgumentException and reject/log the raw input when it contains unrecognized entities"],"exampleFix":"// before: throws IllegalArgumentException(\"Bad HTML quoting for &#39;\")\nString v = HtmlQuoting.unquoteHtmlChars(s);\n\n// after: normalize numeric refs, then unquote\nString v = HtmlQuoting.unquoteHtmlChars(\n    s.replaceAll(\"&#(\\\\d+);\", m -> String.valueOf((char) Integer.parseInt(m.group(1)))));","handlingStrategy":"validation","validationCode":"private static final Pattern OK_ENTITY =\n    Pattern.compile(\"&(amp|apos|gt|lt|quot);\");\nstatic boolean isUnquotable(String s) {\n  if (s == null || s.indexOf('&') < 0) return true;\n  Matcher m = Pattern.compile(\"&[^;&]*;?\").matcher(s);\n  while (m.find()) {\n    if (!OK_ENTITY.matcher(m.group()).matches()) return false;\n  }\n  return true;\n}","typeGuard":null,"tryCatchPattern":"try {\n  value = HtmlQuoting.unquoteHtmlChars(raw);\n} catch (IllegalArgumentException e) {\n  // unknown/numeric entity: reject input or decode with a full unescaper instead\n  value = strictDecodeFallback(raw); // or throw a 400 upstream\n}","preventionTips":["Only round-trip strings through quoteHtmlChars/unquoteHtmlChars as a pair","Convert numeric character references (&#NN;) before calling unquote","For arbitrary HTML use a dedicated unescaper; treat HtmlQuoting as internal to Hadoop web UI"],"tags":["hadoop","html","escaping","parsing","validation"],"backgroundTag":"html-entity-decode-failed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}