diff options
author | Artur Signell <artur@vaadin.com> | 2015-01-28 17:08:15 +0200 |
---|---|---|
committer | Artur Signell <artur@vaadin.com> | 2015-01-29 10:13:00 +0200 |
commit | a66eeb58e8c1144c8d01cc37f727638139db711d (patch) | |
tree | 423a1973d4e7ed38152f18a206ea9c9b2d04c377 | |
parent | a681bf8f13163b67f55ec2d334f44f976d3eb161 (diff) | |
download | vaadin-framework-a66eeb58e8c1144c8d01cc37f727638139db711d.tar.gz vaadin-framework-a66eeb58e8c1144c8d01cc37f727638139db711d.zip |
Do not loop infinitely when encountering an invalid tag name (#16522)
Also do not write to sysout
Change-Id: Idae318a851323cd27b3363d12e8080101e996d9c
3 files changed, 117 insertions, 20 deletions
diff --git a/server/src/com/vaadin/ui/declarative/DesignContext.java b/server/src/com/vaadin/ui/declarative/DesignContext.java index fd83339b76..b298c95320 100644 --- a/server/src/com/vaadin/ui/declarative/DesignContext.java +++ b/server/src/com/vaadin/ui/declarative/DesignContext.java @@ -20,7 +20,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; import org.jsoup.nodes.Attributes; @@ -29,6 +28,7 @@ import org.jsoup.nodes.Element; import org.jsoup.nodes.Node; import com.vaadin.annotations.DesignRoot; +import com.vaadin.shared.util.SharedUtil; import com.vaadin.ui.Component; import com.vaadin.ui.HasComponents; @@ -509,7 +509,7 @@ public class DesignContext implements Serializable { // Otherwise, get the full class name using the prefix to package // mapping. Example: "v-vertical-layout" -> // "com.vaadin.ui.VerticalLayout" - String[] parts = tagName.split("-"); + String[] parts = tagName.split("-", 2); if (parts.length < 2) { throw new DesignException("The tagname '" + tagName + "' is invalid: missing prefix."); @@ -519,24 +519,16 @@ public class DesignContext implements Serializable { if (packageName == null) { throw new DesignException("Unknown tag: " + tagName); } - int firstCharacterIndex = prefixName.length() + 1; // +1 is for '-' - tagName = tagName.substring(firstCharacterIndex, - firstCharacterIndex + 1).toUpperCase(Locale.ENGLISH) - + tagName.substring(firstCharacterIndex + 1); - int i; - while ((i = tagName.indexOf("-")) != -1) { - int length = tagName.length(); - if (i != length - 1) { - tagName = tagName.substring(0, i) - + tagName.substring(i + 1, i + 2).toUpperCase( - Locale.ENGLISH) + tagName.substring(i + 2); - - } else { - // Ends with "-" - System.out.println("A tag name should not end with '-'."); - } + String[] classNameParts = parts[1].split("-"); + String className = ""; + for (String classNamePart : classNameParts) { + // Split will ignore trailing and multiple dashes but that should be + // ok + // <v-button--> will be resolved to <v-button> + // <v--button> will be resolved to <v-button> + className += SharedUtil.capitalize(classNamePart); } - return packageName + "." + tagName; + return packageName + "." + className; } @SuppressWarnings("unchecked") diff --git a/server/tests/src/com/vaadin/tests/design/InvalidTagNames.java b/server/tests/src/com/vaadin/tests/design/InvalidTagNames.java new file mode 100644 index 0000000000..0b6ccf8cb1 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/design/InvalidTagNames.java @@ -0,0 +1,103 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.design; + +import java.io.ByteArrayInputStream; +import java.io.UnsupportedEncodingException; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.ui.Button; +import com.vaadin.ui.Component; +import com.vaadin.ui.declarative.Design; +import com.vaadin.ui.declarative.DesignException; + +public class InvalidTagNames { + + @Test(expected = DesignException.class) + public void tagWithoutDash() { + readDesign("<vbutton>foo</vbutton>"); + } + + @Test + public void emptyTag() { + // JSoup parses empty tags into text nodes + Component c = readDesign("<>foo</>"); + Assert.assertNull(c); + } + + @Test(expected = DesignException.class) + public void onlyPrefix() { + readDesign("<v->foo</v->"); + } + + @Test + public void onlyClass() { + // JSoup will refuse to parse tags starting with - and convert them into + // text nodes instead + Component c = readDesign("<-v>foo</-v>"); + Assert.assertNull(c); + } + + @Test(expected = DesignException.class) + public void unknownClass() { + readDesign("<v-unknownbutton>foo</v-unknownbutton>"); + } + + @Test(expected = DesignException.class) + public void unknownTag() { + readDesign("<x-button></x-button>"); + } + + // @Test(expected = DesignException.class) + // This is a side effect of not actively checking for invalid input. Will be + // parsed currently as <v-button> (this should not be considered API) + public void tagEndsInDash() { + Component c = readDesign("<v-button-></v-button->"); + Assert.assertTrue(c.getClass() == Button.class); + } + + // @Test(expected = DesignException.class) + // This is a side effect of not actively checking for invalid input. Will be + // parsed currently as <v-button> (this should not be considered API) + public void tagEndsInTwoDashes() { + Component c = readDesign("<v-button--></v-button-->"); + Assert.assertTrue(c.getClass() == Button.class); + } + + // @Test(expected = DesignException.class) + // This is a side effect of not actively checking for invalid input. Will be + // parsed currently as <v-button> (this should not be considered API) + public void tagWithTwoDashes() { + Component c = readDesign("<v--button></v--button>"); + Assert.assertTrue(c.getClass() == Button.class); + } + + @Test(expected = DesignException.class) + public void specialCharacters() { + readDesign("<v-button-&!#></v-button-&!#>"); + } + + private Component readDesign(String string) { + try { + return Design.read(new ByteArrayInputStream(string + .getBytes("UTF-8"))); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } +} diff --git a/shared/src/com/vaadin/shared/util/SharedUtil.java b/shared/src/com/vaadin/shared/util/SharedUtil.java index 206041235a..bc5d87b9f5 100644 --- a/shared/src/com/vaadin/shared/util/SharedUtil.java +++ b/shared/src/com/vaadin/shared/util/SharedUtil.java @@ -16,6 +16,7 @@ package com.vaadin.shared.util; import java.io.Serializable; +import java.util.Locale; /** * Misc internal utility methods used by both the server and the client package. @@ -168,7 +169,8 @@ public class SharedUtil implements Serializable { return string.toUpperCase(); } - return string.substring(0, 1).toUpperCase() + string.substring(1); + return string.substring(0, 1).toUpperCase(Locale.ENGLISH) + + string.substring(1); } /** |