diff options
author | Jiri Vanek <[email protected]> | 2013-06-21 12:15:03 +0200 |
---|---|---|
committer | Jiri Vanek <[email protected]> | 2013-06-21 12:15:03 +0200 |
commit | da8ec0b9cba22448fbb5b599bff3e1f5fb8c0bf7 (patch) | |
tree | e3cd2c82fd0eff3b9d9c95b4f67fac27d7d519bc /netx/net | |
parent | 70371886c351800a6fad9bad17777179af2d8584 (diff) |
Added tagsup (optional dependence) as sanitizer for (possibly) invalid xml files
Diffstat (limited to 'netx/net')
-rw-r--r-- | netx/net/sourceforge/jnlp/JNLPCreator.java | 4 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/JNLPFile.java | 72 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/Launcher.java | 10 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/MalformedXMLParser.java | 123 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/Parser.java | 155 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/ParserSettings.java | 27 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/PluginBridge.java | 5 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/XmlParser.java | 183 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/resources/Messages.properties | 1 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/runtime/Boot.java | 14 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java | 7 |
11 files changed, 427 insertions, 174 deletions
diff --git a/netx/net/sourceforge/jnlp/JNLPCreator.java b/netx/net/sourceforge/jnlp/JNLPCreator.java index ca1b94b..4ece458 100644 --- a/netx/net/sourceforge/jnlp/JNLPCreator.java +++ b/netx/net/sourceforge/jnlp/JNLPCreator.java @@ -28,8 +28,8 @@ import java.net.URL; import net.sourceforge.jnlp.cache.UpdatePolicy; public class JNLPCreator { - public JNLPFile create(URL location, Version version, boolean strict, + public JNLPFile create(URL location, Version version, ParserSettings settings, UpdatePolicy policy, URL forceCodebase) throws IOException, ParseException { - return new JNLPFile(location, version, strict, policy, forceCodebase); + return new JNLPFile(location, version, settings, policy, forceCodebase); } } diff --git a/netx/net/sourceforge/jnlp/JNLPFile.java b/netx/net/sourceforge/jnlp/JNLPFile.java index 26bc806..f8c953e 100644 --- a/netx/net/sourceforge/jnlp/JNLPFile.java +++ b/netx/net/sourceforge/jnlp/JNLPFile.java @@ -67,6 +67,9 @@ public class JNLPFile { /** the network location of this JNLP file */ protected URL fileLocation; + /** the ParserSettings which were used to parse this file */ + protected ParserSettings parserSettings = null; + /** A key that uniquely identifies connected instances (main jnlp+ext) */ protected String uniqueKey = null; @@ -145,7 +148,7 @@ public class JNLPFile { * @throws ParseException if the JNLP file was invalid */ public JNLPFile(URL location) throws IOException, ParseException { - this(location, false); // not strict + this(location, new ParserSettings()); } /** @@ -153,12 +156,12 @@ public class JNLPFile { * default policy. * * @param location the location of the JNLP file - * @param strict whether to enforce the spec when + * @param settings the parser settings to use while parsing the file * @throws IOException if an IO exception occurred * @throws ParseException if the JNLP file was invalid */ - public JNLPFile(URL location, boolean strict) throws IOException, ParseException { - this(location, (Version) null, strict); + public JNLPFile(URL location, ParserSettings settings) throws IOException, ParseException { + this(location, (Version) null, settings); } /** @@ -167,12 +170,12 @@ public class JNLPFile { * * @param location the location of the JNLP file * @param version the version of the JNLP file - * @param strict whether to enforce the spec when + * @param settings the parser settings to use while parsing the file * @throws IOException if an IO exception occurred * @throws ParseException if the JNLP file was invalid */ - public JNLPFile(URL location, Version version, boolean strict) throws IOException, ParseException { - this(location, version, strict, JNLPRuntime.getDefaultUpdatePolicy()); + public JNLPFile(URL location, Version version, ParserSettings settings) throws IOException, ParseException { + this(location, version, settings, JNLPRuntime.getDefaultUpdatePolicy()); } /** @@ -186,8 +189,8 @@ public class JNLPFile { * @throws IOException if an IO exception occurred * @throws ParseException if the JNLP file was invalid */ - public JNLPFile(URL location, Version version, boolean strict, UpdatePolicy policy) throws IOException, ParseException { - this(location, version, strict, policy, null); + public JNLPFile(URL location, Version version, ParserSettings settings, UpdatePolicy policy) throws IOException, ParseException { + this(location, version, settings, policy, null); } /** @@ -196,15 +199,16 @@ public class JNLPFile { * * @param location the location of the JNLP file * @param version the version of the JNLP file - * @param strict whether to enforce the spec when + * @param settings the parser settings to use while parsing the file * @param policy the update policy * @param forceCodebase codebase to use if not specified in JNLP file. * @throws IOException if an IO exception occurred * @throws ParseException if the JNLP file was invalid */ - protected JNLPFile(URL location, Version version, boolean strict, UpdatePolicy policy, URL forceCodebase) throws IOException, ParseException { - Node root = Parser.getRootNode(openURL(location, version, policy)); - parse(root, strict, location, forceCodebase); + protected JNLPFile(URL location, Version version, ParserSettings settings, UpdatePolicy policy, URL forceCodebase) throws IOException, ParseException { + InputStream input = openURL(location, version, policy); + this.parserSettings = settings; + parse(input, location, forceCodebase); //Downloads the original jnlp file into the cache if possible //(i.e. If the jnlp file being launched exist locally, but it @@ -231,13 +235,13 @@ public class JNLPFile { * @param location the location of the JNLP file * @param uniqueKey A string that uniquely identifies connected instances * @param version the version of the JNLP file - * @param strict whether to enforce the spec when + * @param settings the parser settings to use while parsing the file * @param policy the update policy * @throws IOException if an IO exception occurred * @throws ParseException if the JNLP file was invalid */ - public JNLPFile(URL location, String uniqueKey, Version version, boolean strict, UpdatePolicy policy) throws IOException, ParseException { - this(location, version, strict, policy); + public JNLPFile(URL location, String uniqueKey, Version version, ParserSettings settings, UpdatePolicy policy) throws IOException, ParseException { + this(location, version, settings, policy); this.uniqueKey = uniqueKey; if (JNLPRuntime.isDebug()) @@ -250,8 +254,9 @@ public class JNLPFile { * @throws IOException if an IO exception occurred * @throws ParseException if the JNLP file was invalid */ - public JNLPFile(InputStream input, boolean strict) throws ParseException { - this(input, null, strict); + public JNLPFile(InputStream input, ParserSettings settings) throws ParseException { + this.parserSettings = settings; + parse(input, null, null); } /** @@ -263,22 +268,11 @@ public class JNLPFile { * @throws IOException if an IO exception occurred * @throws ParseException if the JNLP file was invalid */ - public JNLPFile(InputStream input, URL codebase, boolean strict) throws ParseException { - parse(Parser.getRootNode(input), strict, null, codebase); + public JNLPFile(InputStream input, URL codebase, ParserSettings settings) throws ParseException { + this.parserSettings = settings; + parse(input, null, codebase); } - /** - * Create a JNLPFile from a character stream. - * - * @param input the stream - * @param strict whether to enforce the spec when - * @throws IOException if an IO exception occurred - * @throws ParseException if the JNLP file was invalid - */ - private JNLPFile(Reader input, boolean strict) throws ParseException { - // todo: now that we are using NanoXML we can use a Reader - //parse(Parser.getRootNode(input), strict, null); - } /** * Open the jnlp file URL from the cache if there, otherwise @@ -338,6 +332,13 @@ public class JNLPFile { } /** + * Returns the ParserSettings that was used to parse this file + */ + public ParserSettings getParserSettings() { + return parserSettings; + } + + /** * Returns the JNLP file's version. */ public Version getFileVersion() { @@ -685,15 +686,16 @@ public class JNLPFile { * from the constructor. * * @param root the root node - * @param strict whether to enforce the spec when + * @param settings the parser settings to use while parsing the file * @param location the file location or null */ - private void parse(Node root, boolean strict, URL location, URL forceCodebase) throws ParseException { + private void parse(InputStream input, URL location, URL forceCodebase) throws ParseException { try { //if (location != null) // location = new URL(location, "."); // remove filename - Parser parser = new Parser(this, location, root, strict, true, forceCodebase); // true == allow extensions + Node root = Parser.getRootNode(input, parserSettings); + Parser parser = new Parser(this, location, root, parserSettings, forceCodebase); // true == allow extensions // JNLP tag information specVersion = parser.getSpecVersion(); diff --git a/netx/net/sourceforge/jnlp/Launcher.java b/netx/net/sourceforge/jnlp/Launcher.java index 11ca09f..efb1915 100644 --- a/netx/net/sourceforge/jnlp/Launcher.java +++ b/netx/net/sourceforge/jnlp/Launcher.java @@ -477,12 +477,12 @@ public class Launcher { try { JNLPFile file = null; - file = new JNLPFile(location, parserSettings.isStrict()); + file = new JNLPFile(location, parserSettings); if (fromSource) { // Launches the jnlp file where this file originated. if (file.getSourceLocation() != null) { - file = new JNLPFile(file.getSourceLocation(), parserSettings.isStrict()); + file = new JNLPFile(file.getSourceLocation(), parserSettings); } } return file; @@ -504,9 +504,11 @@ public class Launcher { JNLPFile file = null; try { - file = new JNLPFile(location, (Version) null, true, updatePolicy); // strict + ParserSettings settings = new ParserSettings(true, true, false); + file = new JNLPFile(location, (Version) null, settings, updatePolicy); // strict } catch (ParseException ex) { - file = new JNLPFile(location, (Version) null, false, updatePolicy); + ParserSettings settings = new ParserSettings(false, true, true); + file = new JNLPFile(location, (Version) null, settings, updatePolicy); // only here if strict failed but lax did not fail LaunchException lex = diff --git a/netx/net/sourceforge/jnlp/MalformedXMLParser.java b/netx/net/sourceforge/jnlp/MalformedXMLParser.java new file mode 100644 index 0000000..04cfe19 --- /dev/null +++ b/netx/net/sourceforge/jnlp/MalformedXMLParser.java @@ -0,0 +1,123 @@ +/* + Copyright (C) 2013 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea 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 for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + */ +package net.sourceforge.jnlp; + +import static net.sourceforge.jnlp.runtime.Translator.R; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +import net.sourceforge.jnlp.runtime.JNLPRuntime; + +import org.ccil.cowan.tagsoup.HTMLSchema; +import org.ccil.cowan.tagsoup.Parser; +import org.ccil.cowan.tagsoup.XMLWriter; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + +/** + * An specialized {@link XMLParser} that uses TagSoup[1] to parse + * malformed XML + * + * Used by net.sourceforge.jnlp.Parser + * + * [1] http://home.ccil.org/~cowan/XML/tagsoup/ + */ +public class MalformedXMLParser extends XMLParser { + + /** + * Parses the data from an {@link InputStream} to create a XML tree. + * Returns a {@link Node} representing the root of the tree. + * + * @param input the {@link InputStream} to read data from + * @throws ParseException if an exception occurs while parsing the input + */ + @Override + public Node getRootNode(InputStream input) throws ParseException { + if (JNLPRuntime.isDebug()) { + System.out.println("Using MalformedXMLParser"); + } + InputStream xmlInput = xmlizeInputStream(input); + return super.getRootNode(xmlInput); + } + + /** + * Reads malformed XML from the InputStream original and returns a new + * InputStream which can be used to read a well-formed version of the input + * + * @param original + * @return an {@link InputStream} which can be used to read a well-formed + * version of the input XML + * @throws ParseException + */ + private InputStream xmlizeInputStream(InputStream original) throws ParseException { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + HTMLSchema schema = new HTMLSchema(); + XMLReader reader = new Parser(); + + //TODO walk through the javadoc and tune more settings + //see tagsoup javadoc for details + reader.setProperty(Parser.schemaProperty, schema); + reader.setFeature(Parser.bogonsEmptyFeature, false); + reader.setFeature(Parser.ignorableWhitespaceFeature, true); + reader.setFeature(Parser.ignoreBogonsFeature, false); + + Writer writeger = new OutputStreamWriter(out); + XMLWriter x = new XMLWriter(writeger); + + reader.setContentHandler(x); + + InputSource s = new InputSource(original); + + reader.parse(s); + return new ByteArrayInputStream(out.toByteArray()); + } catch (SAXException e) { + throw new ParseException(R("PBadXML"), e); + } catch (IOException e) { + throw new ParseException(R("PBadXML"), e); + } + + } + +} diff --git a/netx/net/sourceforge/jnlp/Parser.java b/netx/net/sourceforge/jnlp/Parser.java index a825a5b..efa6bcd 100644 --- a/netx/net/sourceforge/jnlp/Parser.java +++ b/netx/net/sourceforge/jnlp/Parser.java @@ -1,5 +1,5 @@ // Copyright (C) 2001-2003 Jon A. Maxwell (JAM) -// Copyright (C) 2012 Red Hat, Inc. +// Copyright (C) 2009-2013 Red Hat, Inc. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,16 +20,14 @@ package net.sourceforge.jnlp; import static net.sourceforge.jnlp.runtime.Translator.R; import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.net.*; import java.util.*; -//import javax.xml.parsers.*; // commented to use right Node -//import org.w3c.dom.*; // class for using Tiny XML | NanoXML -//import org.xml.sax.*; -//import gd.xml.tiny.*; + import net.sourceforge.jnlp.UpdateDesc.Check; import net.sourceforge.jnlp.UpdateDesc.Policy; import net.sourceforge.jnlp.runtime.JNLPRuntime; -import net.sourceforge.nanoxml.*; /** * Contains methods to parse an XML document into a JNLPFile. @@ -106,12 +104,11 @@ class Parser { * @param file the (uninitialized) file reference * @param base if codebase is not specified, a default base for relative URLs * @param root the root node - * @param strict whether to enforce strict compliance with the JNLP spec - * @param allowExtensions whether to allow extensions to the JNLP spec + * @param settings the parser settings to use when parsing the JNLP file * @throws ParseException if the JNLP file is invalid */ - public Parser(JNLPFile file, URL base, Node root, boolean strict, boolean allowExtensions) throws ParseException { - this(file, base, root, strict, allowExtensions, null); + public Parser(JNLPFile file, URL base, Node root, ParserSettings settings) throws ParseException { + this(file, base, root, settings, null); } /** @@ -126,16 +123,15 @@ class Parser { * @param file the (uninitialized) file reference * @param base if codebase is not specified, a default base for relative URLs * @param root the root node - * @param strict whether to enforce strict compliance with the JNLP spec - * @param allowExtensions whether to allow extensions to the JNLP spec + * @param settings the parser settings to use when parsing the JNLP file * @param codebase codebase to use if we did not parse one from JNLP file. * @throws ParseException if the JNLP file is invalid */ - public Parser(JNLPFile file, URL base, Node root, boolean strict, boolean allowExtensions, URL codebase) throws ParseException { + public Parser(JNLPFile file, URL base, Node root, ParserSettings settings, URL codebase) throws ParseException { this.file = file; this.root = root; - this.strict = strict; - this.allowExtensions = allowExtensions; + this.strict = settings.isStrict(); + this.allowExtensions = settings.isExtensionAllowed(); // ensure it's a JNLP node if (root == null || !root.getNodeName().equals("jnlp")) @@ -1265,116 +1261,33 @@ class Parser { * * @throws ParseException if the JNLP file is invalid */ - public static Node getRootNode(InputStream input) throws ParseException { - try { - /* SAX - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setValidating(false); - factory.setNamespaceAware(true); - DocumentBuilder builder = factory.newDocumentBuilder(); - builder.setErrorHandler(errorHandler); - - Document doc = builder.parse(input); - return doc.getDocumentElement(); - */ - - /* TINY - Node document = new Node(TinyParser.parseXML(input)); - Node jnlpNode = getChildNode(document, "jnlp"); // skip comments - */ - - //A BufferedInputStream is used to allow marking and reseting - //of a stream. - BufferedInputStream bs = new BufferedInputStream(input); - - /* NANO */ - final XMLElement xml = new XMLElement(); - final PipedInputStream pin = new PipedInputStream(); - final PipedOutputStream pout = new PipedOutputStream(pin); - final InputStreamReader isr = new InputStreamReader(bs, getEncoding(bs)); - // Clean the jnlp xml file of all comments before passing - // it to the parser. - new Thread( - new Runnable() { - public void run() { - (new XMLElement()).sanitizeInput(isr, pout); - try { - pout.close(); - } catch (IOException ioe) { - ioe.printStackTrace(); - } - } - }).start(); - xml.parseFromReader(new InputStreamReader(pin)); - Node jnlpNode = new Node(xml); - return jnlpNode; - } catch (Exception ex) { - throw new ParseException(R("PBadXML"), ex); + public static Node getRootNode(InputStream input, ParserSettings settings) throws ParseException { + String className = null; + if (settings.isMalformedXmlAllowed()) { + className = "net.sourceforge.jnlp.MalformedXMLParser"; + } else { + className = "net.sourceforge.jnlp.XMLParser"; } - } - /** - * Returns the name of the encoding used in this InputStream. - * - * @param input the InputStream - * @return a String representation of encoding - */ - private static String getEncoding(InputStream input) throws IOException { - //Fixme: This only recognizes UTF-8, UTF-16, and - //UTF-32, which is enough to parse the prolog portion of xml to - //find out the exact encoding (if it exists). The reason being - //there could be other encodings, such as ISO 8859 which is 8-bits - //but it supports latin characters. - //So what needs to be done is to parse the prolog and retrieve - //the exact encoding from it. - - int[] s = new int[4]; - String encoding = "UTF-8"; - - //Determine what the first four bytes are and store - //them into an int array. - input.mark(4); - for (int i = 0; i < 4; i++) { - s[i] = input.read(); - } - input.reset(); - - //Set the encoding base on what the first four bytes of the - //inputstream turn out to be (following the information from - //www.w3.org/TR/REC-xml/#sec-guessing). - if (s[0] == 255) { - if (s[1] == 254) { - if (s[2] != 0 || s[3] != 0) { - encoding = "UnicodeLittle"; - } else { - encoding = "X-UTF-32LE-BOM"; - } + try { + Class<?> klass = null; + try { + klass = Class.forName(className); + } catch (ClassNotFoundException e) { + klass = Class.forName("net.sourceforge.jnlp.XMLParser"); } - } else if (s[0] == 254 && s[1] == 255 && (s[2] != 0 || - s[3] != 0)) { - encoding = "UTF-16"; - - } else if (s[0] == 0 && s[1] == 0 && s[2] == 254 && - s[3] == 255) { - encoding = "X-UTF-32BE-BOM"; - - } else if (s[0] == 0 && s[1] == 0 && s[2] == 0 && - s[3] == 60) { - encoding = "UTF-32BE"; - - } else if (s[0] == 60 && s[1] == 0 && s[2] == 0 && - s[3] == 0) { - encoding = "UTF-32LE"; - - } else if (s[0] == 0 && s[1] == 60 && s[2] == 0 && - s[3] == 63) { - encoding = "UTF-16BE"; - } else if (s[0] == 60 && s[1] == 0 && s[2] == 63 && - s[3] == 0) { - encoding = "UTF-16LE"; - } + Object instance = klass.newInstance(); + Method m = klass.getMethod("getRootNode", InputStream.class); - return encoding; + return (Node) m.invoke(instance, input); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof ParseException) { + throw (ParseException)(e.getCause()); + } + throw new ParseException(R("PBadXML"), e); + } catch (Exception e) { + throw new ParseException(R("PBadXML"), e); + } } } diff --git a/netx/net/sourceforge/jnlp/ParserSettings.java b/netx/net/sourceforge/jnlp/ParserSettings.java index b0a69e3..de781d9 100644 --- a/netx/net/sourceforge/jnlp/ParserSettings.java +++ b/netx/net/sourceforge/jnlp/ParserSettings.java @@ -35,7 +35,6 @@ obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ - package net.sourceforge.jnlp; /** @@ -46,16 +45,34 @@ package net.sourceforge.jnlp; public class ParserSettings { private final boolean isStrict; + private final boolean extensionAllowed; + private final boolean malformedXmlAllowed; + /** Create a new ParserSettings with the defautl parser settings */ public ParserSettings() { - isStrict = false; + this(false, true, true); + } + + /** Create a new ParserSettings object */ + public ParserSettings(boolean strict, boolean extensionAllowed, boolean malformedXmlAllowed) { + this.isStrict = strict; + this.extensionAllowed = extensionAllowed; + this.malformedXmlAllowed = malformedXmlAllowed; } - public ParserSettings(boolean strict) { - isStrict = strict; + /** @return true if extensions to the spec are allowed */ + public boolean isExtensionAllowed() { + return extensionAllowed; } + /** @return true if parsing malformed xml is allowed */ + public boolean isMalformedXmlAllowed() { + return malformedXmlAllowed; + } + + /** @return true if strict parsing mode is to be used */ public boolean isStrict() { return isStrict; } -} + +}
\ No newline at end of file diff --git a/netx/net/sourceforge/jnlp/PluginBridge.java b/netx/net/sourceforge/jnlp/PluginBridge.java index d069479..9163404 100644 --- a/netx/net/sourceforge/jnlp/PluginBridge.java +++ b/netx/net/sourceforge/jnlp/PluginBridge.java @@ -96,14 +96,15 @@ public class PluginBridge extends JNLPFile { try { // Use codeBase as the context for the URL. If jnlp_href's // value is a complete URL, it will replace codeBase's context. + ParserSettings defaultSettings = new ParserSettings(); URL jnlp = new URL(codeBase, params.getJNLPHref()); JNLPFile jnlpFile = null; if (params.getJNLPEmbedded() != null) { InputStream jnlpInputStream = new ByteArrayInputStream(decodeBase64String(params.getJNLPEmbedded())); - jnlpFile = new JNLPFile(jnlpInputStream, codeBase, false); + jnlpFile = new JNLPFile(jnlpInputStream, codeBase, defaultSettings); } else { - jnlpFile = jnlpCreator.create(jnlp, null, false, JNLPRuntime.getDefaultUpdatePolicy(), codeBase); + jnlpFile = jnlpCreator.create(jnlp, null, defaultSettings, JNLPRuntime.getDefaultUpdatePolicy(), codeBase); } if (jnlpFile.isApplet()) diff --git a/netx/net/sourceforge/jnlp/XmlParser.java b/netx/net/sourceforge/jnlp/XmlParser.java new file mode 100644 index 0000000..05080ea --- /dev/null +++ b/netx/net/sourceforge/jnlp/XmlParser.java @@ -0,0 +1,183 @@ +/* + Copyright (C) 2013 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea 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 for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + */ + +package net.sourceforge.jnlp; + +import static net.sourceforge.jnlp.runtime.Translator.R; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; + +import net.sourceforge.nanoxml.XMLElement; + +//import javax.xml.parsers.*; // commented to use right Node +//import org.w3c.dom.*; // class for using Tiny XML | NanoXML +//import org.xml.sax.*; +//import gd.xml.tiny.*; + +/** + * A gateway to the actual implementation of the parsers. + * + * Used by net.sourceforge.jnlp.Parser + */ +class XMLParser { + + /** + * Parses input from an InputStream and returns a Node representing the + * root of the parse tree. + * + * @param input the {@link InputStream} containing the XML + * @return a {@link Node} representing the root of the parsed XML + * @throws ParseException + */ + public Node getRootNode(InputStream input) throws ParseException { + + try { + /* SAX + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setValidating(false); + factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); + builder.setErrorHandler(errorHandler); + + Document doc = builder.parse(input); + return doc.getDocumentElement(); + */ + + /* TINY + Node document = new Node(TinyParser.parseXML(input)); + Node jnlpNode = getChildNode(document, "jnlp"); // skip comments + */ + + //A BufferedInputStream is used to allow marking and reseting + //of a stream. + BufferedInputStream bs = new BufferedInputStream(input); + + /* NANO */ + final XMLElement xml = new XMLElement(); + final PipedInputStream pin = new PipedInputStream(); + final PipedOutputStream pout = new PipedOutputStream(pin); + final InputStreamReader isr = new InputStreamReader(bs, getEncoding(bs)); + // Clean the jnlp xml file of all comments before passing + // it to the parser. + new Thread( + new Runnable() { + public void run() { + (new XMLElement()).sanitizeInput(isr, pout); + try { + pout.close(); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } + }).start(); + xml.parseFromReader(new InputStreamReader(pin)); + Node jnlpNode = new Node(xml); + return jnlpNode; + } catch (Exception ex) { + throw new ParseException(R("PBadXML"), ex); + } + } + + /** + * Returns the name of the encoding used in this InputStream. + * + * @param input the InputStream + * @return a String representation of encoding + */ + private static String getEncoding(InputStream input) throws IOException { + //Fixme: This only recognizes UTF-8, UTF-16, and + //UTF-32, which is enough to parse the prolog portion of xml to + //find out the exact encoding (if it exists). The reason being + //there could be other encodings, such as ISO 8859 which is 8-bits + //but it supports latin characters. + //So what needs to be done is to parse the prolog and retrieve + //the exact encoding from it. + + int[] s = new int[4]; + String encoding = "UTF-8"; + + //Determine what the first four bytes are and store + //them into an int array. + input.mark(4); + for (int i = 0; i < 4; i++) { + s[i] = input.read(); + } + input.reset(); + + //Set the encoding base on what the first four bytes of the + //inputstream turn out to be (following the information from + //www.w3.org/TR/REC-xml/#sec-guessing). + if (s[0] == 255) { + if (s[1] == 254) { + if (s[2] != 0 || s[3] != 0) { + encoding = "UnicodeLittle"; + } else { + encoding = "X-UTF-32LE-BOM"; + } + } + } else if (s[0] == 254 && s[1] == 255 && (s[2] != 0 || + s[3] != 0)) { + encoding = "UTF-16"; + + } else if (s[0] == 0 && s[1] == 0 && s[2] == 254 && + s[3] == 255) { + encoding = "X-UTF-32BE-BOM"; + + } else if (s[0] == 0 && s[1] == 0 && s[2] == 0 && + s[3] == 60) { + encoding = "UTF-32BE"; + + } else if (s[0] == 60 && s[1] == 0 && s[2] == 0 && + s[3] == 0) { + encoding = "UTF-32LE"; + + } else if (s[0] == 0 && s[1] == 60 && s[2] == 0 && + s[3] == 63) { + encoding = "UTF-16BE"; + } else if (s[0] == 60 && s[1] == 0 && s[2] == 63 && + s[3] == 0) { + encoding = "UTF-16LE"; + } + + return encoding; + } +} diff --git a/netx/net/sourceforge/jnlp/resources/Messages.properties b/netx/net/sourceforge/jnlp/resources/Messages.properties index 2691005..d0de783 100644 --- a/netx/net/sourceforge/jnlp/resources/Messages.properties +++ b/netx/net/sourceforge/jnlp/resources/Messages.properties @@ -189,6 +189,7 @@ BONoupdate = Disables checking for updates. BOHeadless = Disables download window, other UIs. BOStrict = Enables strict checking of JNLP file format. BOViewer = Shows the trusted certificate viewer. +BOXml = Uses a strict XML parser to parse the JNLP file. BXnofork = Do not create another JVM. BXclearcache= Clean the JNLP application cache. BXignoreheaders= Skip jar header verification. diff --git a/netx/net/sourceforge/jnlp/runtime/Boot.java b/netx/net/sourceforge/jnlp/runtime/Boot.java index 9b69660..4af893a 100644 --- a/netx/net/sourceforge/jnlp/runtime/Boot.java +++ b/netx/net/sourceforge/jnlp/runtime/Boot.java @@ -102,6 +102,7 @@ public final class Boot implements PrivilegedAction<Void> { + " -noupdate " + R("BONoupdate") + "\n" + " -headless " + R("BOHeadless") + "\n" + " -strict " + R("BOStrict") + "\n" + + " -xml " + R("BOXml") + "\n" + " -Xnofork " + R("BXnofork") + "\n" + " -Xclearcache " + R("BXclearcache") + "\n" + " -Xignoreheaders " + R("BXignoreheaders") + "\n" @@ -197,9 +198,18 @@ public final class Boot implements PrivilegedAction<Void> { extra.put("arguments", getOptions("-arg")); extra.put("parameters", getOptions("-param")); extra.put("properties", getOptions("-property")); + boolean strict = false; + boolean malformedXmlAllowed = true; - boolean strict = (null != getOption("-strict")); - ParserSettings settings = new ParserSettings(strict); + if (null != getOption("-strict")) { + strict = true; + } + + if (null != getOption("-xml")) { + malformedXmlAllowed = false; + } + + ParserSettings settings = new ParserSettings(strict, true, malformedXmlAllowed); try { Launcher launcher = new Launcher(false); diff --git a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java index 46212d7..a74f541 100644 --- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java +++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java @@ -76,6 +76,7 @@ import net.sourceforge.jnlp.LaunchDesc; import net.sourceforge.jnlp.LaunchException; import net.sourceforge.jnlp.NullJnlpFileException; import net.sourceforge.jnlp.ParseException; +import net.sourceforge.jnlp.ParserSettings; import net.sourceforge.jnlp.PluginBridge; import net.sourceforge.jnlp.ResourcesDesc; import net.sourceforge.jnlp.SecurityDesc; @@ -460,7 +461,7 @@ public class JNLPClassLoader extends URLClassLoader { * @param policy the update policy to use when downloading resources * @param mainName Overrides the main class name of the application */ - public static JNLPClassLoader getInstance(URL location, String uniqueKey, Version version, UpdatePolicy policy, String mainName) + public static JNLPClassLoader getInstance(URL location, String uniqueKey, Version version,ParserSettings settings, UpdatePolicy policy, String mainName) throws IOException, ParseException, LaunchException { JNLPClassLoader loader; @@ -469,7 +470,7 @@ public class JNLPClassLoader extends URLClassLoader { loader = uniqueKeyToLoader.get(uniqueKey); if (loader == null || !location.equals(loader.getJNLPFile().getFileLocation())) { - JNLPFile jnlpFile = new JNLPFile(location, uniqueKey, version, false, policy); + JNLPFile jnlpFile = new JNLPFile(location, uniqueKey, version, settings, policy); loader = getInstance(jnlpFile, policy, mainName); } @@ -504,7 +505,7 @@ public class JNLPClassLoader extends URLClassLoader { for (int i = 0; i < ext.length; i++) { try { String uniqueKey = this.getJNLPFile().getUniqueKey(); - JNLPClassLoader loader = getInstance(ext[i].getLocation(), uniqueKey, ext[i].getVersion(), updatePolicy, mainClass); + JNLPClassLoader loader = getInstance(ext[i].getLocation(), uniqueKey, ext[i].getVersion(), file.getParserSettings(), updatePolicy, mainClass); loaderList.add(loader); } catch (Exception ex) { ex.printStackTrace(); |