7165725: JAVA6 HTML PARSER CANNOT PARSE MULTIPLE SCRIPT TAGS IN A LINE CORRECTLY
Reviewed-by: alexsch
--- a/jdk/src/share/classes/javax/swing/text/html/parser/Parser.java Fri Jun 08 22:21:53 2012 +0400
+++ b/jdk/src/share/classes/javax/swing/text/html/parser/Parser.java Sat Jun 09 17:42:46 2012 +0400
@@ -1986,8 +1986,6 @@
if (i == SCRIPT_END_TAG.length) {
/* '</script>' tag detected */
- /* Here, ch == '>' */
- ch = readCh();
/* Here, ch == the first character after </script> */
return;
} else {
@@ -2060,6 +2058,8 @@
handleComment(str.toCharArray());
endTag(false);
lastBlockStartPos = currentPosition;
+
+ continue;
} else {
switch (c) {
case '<':
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/text/html/parser/Parser/7165725/bug7165725.java Sat Jun 09 17:42:46 2012 +0400
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ @bug 7165725
+ @summary Tests if HTML parser can handle successive script tags in a line
+ and it does not call false text callback after script tags.
+ @run main bug7165725
+*/
+
+import sun.awt.SunToolkit;
+
+import java.awt.BorderLayout;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import javax.swing.*;
+import javax.swing.text.AbstractDocument.AbstractElement;
+import javax.swing.text.AbstractDocument;
+import javax.swing.text.Document;
+import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.html.HTML;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
+import javax.swing.text.html.parser.ParserDelegator;
+
+public class bug7165725 extends JFrame {
+ private static class GoldenElement {
+
+ private String goldenName;
+ private List<GoldenElement> goldenChildren;
+
+ GoldenElement(String goldenName, GoldenElement... goldenChildren){
+ this.goldenName = goldenName;
+ if (goldenChildren != null) {
+ this.goldenChildren = Arrays.asList(goldenChildren);
+ } else {
+ this.goldenChildren = new ArrayList<>();
+ }
+ }
+
+ // throws RuntimeException if not ok
+ public void checkStructureEquivalence(AbstractDocument.AbstractElement elem) {
+ String name = elem.getName();
+ if (!goldenName.equals(name)) {
+ throw new RuntimeException("Bad structure: expected element name is '" + goldenName + "' but the actual name was '" + name + "'.");
+ }
+ int goldenChildCount = goldenChildren.size();
+ int childCount = elem.getChildCount();
+ if (childCount != goldenChildCount) {
+ System.out.print("D: children: ");
+ for (int i = 0; i < childCount; i++) {
+ System.out.print(" " + elem.getElement(i).getName());
+ }
+ System.out.println("");
+ System.out.print("D: goldenChildren: ");
+ for (GoldenElement ge : goldenChildren) {
+ System.out.print(" " + ge.goldenName);
+ }
+ System.out.println("");
+
+ throw new RuntimeException("Bad structure: expected child count of element '" + goldenName + "' is '" + goldenChildCount + "' but the actual count was '" + childCount + "'.");
+ }
+ for (int i = 0; i < childCount; i++) {
+ AbstractDocument.AbstractElement nextElem = (AbstractDocument.AbstractElement) elem.getElement(i);
+ GoldenElement goldenElement = goldenChildren.get(i);
+ goldenElement.checkStructureEquivalence(nextElem);
+ }
+ }
+ }
+
+ private JEditorPane editorPane;
+ public void execute(final String urlStr, final GoldenElement goldenElement) throws Exception {
+ System.out.println();
+ System.out.println("***** TEST: " + urlStr + " *****");
+ System.out.println();
+
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ try {
+ editorPane = new JEditorPane();
+ editorPane.setEditorKit(new HTMLEditorKit() {
+ public Document createDefaultDocument() {
+ AbstractDocument doc =
+ (AbstractDocument) super.createDefaultDocument();
+ doc.setAsynchronousLoadPriority(-1);
+ return doc;
+ }
+ });
+ editorPane.setPage(new URL(urlStr));
+ } catch (IOException ex) {
+ throw new RuntimeException("Test failed", ex);
+ }
+ editorPane.setEditable(false);
+ JScrollPane scroller = new JScrollPane();
+ JViewport vp = scroller.getViewport();
+ vp.add(editorPane);
+ add(scroller, BorderLayout.CENTER);
+ setDefaultCloseOperation(EXIT_ON_CLOSE);
+ setSize(400, 400);
+ setLocationRelativeTo(null);
+ setVisible(true);
+ }
+ });
+
+ ((SunToolkit) SunToolkit.getDefaultToolkit()).realSync();
+
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ HTMLDocument doc = (HTMLDocument) editorPane.getDocument();
+ doc.dump(System.out);
+ goldenElement.checkStructureEquivalence((AbstractElement) doc.getDefaultRootElement());
+ dispose();
+ }
+ });
+
+ System.out.println();
+ System.out.println("*********************************");
+ System.out.println();
+ }
+
+ public static void main(String[] args) throws Exception {
+
+ String dirURL = getDirURL();
+
+ System.out.println("dirURL = " + dirURL);
+
+ new bug7165725().execute(dirURL + "successive-script-tag.html", createSuccessiveScriptTags());
+ new bug7165725().execute(dirURL + "false-text-after-script.html", createFalseTextAfterScript());
+
+ checkByCallbackForSuccessiveScript();
+ checkByCallbackForFalseTextAfterScript();
+
+ System.out.println();
+ System.out.println();
+ System.out.println("Test passed.");
+ }
+
+ static String getDirURL() {
+ return "file:///" +
+ new File(System.getProperty("test.src", ".")).getAbsolutePath() +
+ File.separator;
+ }
+
+ static String getParsedContentOneLine(String path) throws Exception {
+ File f = new File(path);
+ FileReader fr = new FileReader(f);
+ ParserDelegator pd = new ParserDelegator();
+ SBParserCallback sbcallback = new SBParserCallback();
+ pd.parse(fr, sbcallback, true);
+ fr.close();
+ return sbcallback.getStringOneLine();
+ }
+
+ static String getParsedContentOneLine(URL url) throws Exception {
+ return getParsedContentOneLine(url.getPath());
+ }
+
+ static void checkByCallbackForSuccessiveScript() throws Exception {
+ String content = getParsedContentOneLine(new URL(getDirURL() + "successive-script-tag.html"));
+ if (!content.matches(".*<script .*/js/js1\\.js.*<script .*/js/js2\\.js.*<script .*/js/js3\\.js.*"))
+ throw new RuntimeException("Failed to lookup script tags/attributes.");
+ if (!content.matches(".*<style .*stylesheets/base\\.css.*<style .*stylesheets/adv\\.css.*"))
+ throw new RuntimeException("Failed to lookup style tags.");
+ }
+
+ static void checkByCallbackForFalseTextAfterScript() throws Exception {
+ String content = getParsedContentOneLine(new URL(getDirURL() + "false-text-after-script.html"));
+ final int bodyIdx = content.indexOf("<body ");
+ if (bodyIdx > 0) {
+ String sbody = content.substring(bodyIdx);
+ // There should be no Text(...) in this html
+ if (sbody.indexOf("Text(") >= 0)
+ throw new RuntimeException("Unexpected text found.");
+ } else {
+ throw new RuntimeException("Failed to find body tag.");
+ }
+ }
+
+ private static GoldenElement createSuccessiveScriptTags() {
+ return new GoldenElement("html",
+ new GoldenElement("head",
+ new GoldenElement("p-implied",
+ new GoldenElement("title"),
+ new GoldenElement("title"),
+ new GoldenElement("script"),
+ new GoldenElement("comment"),
+ new GoldenElement("script"),
+ new GoldenElement("script"),
+ new GoldenElement("comment"),
+ new GoldenElement("script"),
+ new GoldenElement("script"),
+ new GoldenElement("comment"),
+ new GoldenElement("script"),
+ new GoldenElement("content"))),
+ new GoldenElement("body",
+ new GoldenElement("p-implied",
+ new GoldenElement("content"))));
+ }
+
+ private static GoldenElement createFalseTextAfterScript() {
+ return new GoldenElement("html",
+ new GoldenElement("head",
+ new GoldenElement("p-implied",
+ new GoldenElement("title"),
+ new GoldenElement("title"),
+ new GoldenElement("content"))),
+ new GoldenElement("body",
+ new GoldenElement("form",
+ new GoldenElement("p-implied",
+ new GoldenElement("input"),
+ new GoldenElement("input"),
+ new GoldenElement("content"))),
+ new GoldenElement("p-implied",
+ new GoldenElement("script"),
+ new GoldenElement("comment"),
+ new GoldenElement("script"),
+ new GoldenElement("script"),
+ new GoldenElement("comment"),
+ new GoldenElement("script"),
+ new GoldenElement("content"))));
+ }
+
+ static class SBParserCallback extends HTMLEditorKit.ParserCallback
+ {
+ private int indentSize = 0;
+ private ArrayList<String> elist = new ArrayList<>();
+
+ public String getStringOneLine() {
+ StringBuilder sb = new StringBuilder();
+ for (String s : elist) sb.append(s);
+ return sb.toString();
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ for (String s : elist) sb.append(s + "\n");
+ return sb.toString();
+ }
+
+ protected void indent() {
+ indentSize += 3;
+ }
+ protected void unIndent() {
+ indentSize -= 3; if (indentSize < 0) indentSize = 0;
+ }
+
+ protected String pIndent() {
+ StringBuilder sb = new StringBuilder();
+ for(int i = 0; i < indentSize; i++) sb.append(" ");
+ return sb.toString();
+ }
+
+ public void handleText(char[] data, int pos) {
+ elist.add(pIndent() + "Text(" + data.length + " chars) \"" + new String(data) + "\"");
+ }
+
+ public void handleComment(char[] data, int pos) {
+ elist.add(pIndent() + "Comment(" + data.length + " chars)");
+ }
+
+ public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
+ elist.add(pIndent() + "Tag start(<" + t.toString() + " " + a + ">, " +
+ a.getAttributeCount() + " attrs)");
+ indent();
+ }
+
+ public void handleEndTag(HTML.Tag t, int pos) {
+ unIndent();
+ elist.add(pIndent() + "Tag end(</" + t.toString() + ">)");
+ }
+
+ public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) {
+ elist.add(pIndent() + "Tag(<" + t.toString() + ">, " +
+ a.getAttributeCount() + " attrs)");
+ }
+
+ public void handleError(String errorMsg, int pos){
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/text/html/parser/Parser/7165725/false-text-after-script.html Sat Jun 09 17:42:46 2012 +0400
@@ -0,0 +1,20 @@
+<html>
+<head> <title> Testing </title> </head>
+<body>
+<form>
+
+ <input type="text" name="text1" >
+ <input type="button" name="button1" value="button" onclick="test1(this.form)">
+
+</form>
+
+<SCRIPT LANGUAGE="JavaScript">
+ function test1(form) {
+ alert(form.text1.value);
+ }
+</SCRIPT>
+<SCRIPT>
+ history.forward();
+</SCRIPT>
+</body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/text/html/parser/Parser/7165725/successive-script-tag.html Sat Jun 09 17:42:46 2012 +0400
@@ -0,0 +1,8 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head><title>my title</title>
+ <script src="../../js/js1.js" language="JavaScript"></script><script src="../../js/js2.js" language="JavaScript"></script><script src="../../js/js3.js" language="JavaScript"></script><style type="text/css" media="screen">@import "stylesheets/base.css";</style><style type="text/css" media="screen">@import "stylesheets/adv.css";</style>
+</head>
+<body>
+</body>
+</html>