Allow invalid HTML to be in Razor pages.

- Modified the TagHelperParseTreeRewriter to not remove invalid HTML snippets.
- Added tests to validate invalid HTML is allowed.

#212
This commit is contained in:
N. Taylor Mullen 2014-10-28 12:52:56 -07:00
parent 39accef1ad
commit 8d4bdbdb84
4 changed files with 136 additions and 3 deletions

View File

@ -56,8 +56,10 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
// Get tag name of the current block (doesn't matter if it's an end or start tag)
var tagName = GetTagName(childBlock);
// Could not determine tag name, it can't be a TagHelper, continue on and track the element.
if (tagName == null)
{
_currentBlock.Children.Add(child);
continue;
}
@ -224,9 +226,14 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
}
var childSpan = (Span)child;
var textSymbol = childSpan.Symbols.FirstHtmlSymbolAs(HtmlSymbolType.Text);
var textSymbol = childSpan.Symbols.FirstHtmlSymbolAs(HtmlSymbolType.WhiteSpace | HtmlSymbolType.Text);
return textSymbol != null ? textSymbol.Content : null;
if (textSymbol == null)
{
return null;
}
return textSymbol.Type == HtmlSymbolType.WhiteSpace ? null : textSymbol.Content;
}
private static bool IsSelfClosing(Block beginTagBlock)

View File

@ -1,8 +1,11 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.AspNet.Razor.Tokenizer.Symbols
{
[Flags]
public enum HtmlSymbolType
{
Unknown,

View File

@ -49,7 +49,7 @@ namespace Microsoft.AspNet.Razor.Tokenizer.Symbols
/// <returns>The first <see cref="HtmlSymbol"/> of type <paramref name="type"/>.</returns>
public static HtmlSymbol FirstHtmlSymbolAs(this IEnumerable<ISymbol> symbols, HtmlSymbolType type)
{
return symbols.OfType<HtmlSymbol>().FirstOrDefault(sym => sym.Type == type);
return symbols.OfType<HtmlSymbol>().FirstOrDefault(sym => (type & sym.Type) == sym.Type);
}
}
}

View File

@ -92,6 +92,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
};
}
}
[Theory]
[MemberData(nameof(IncompleteHelperBlockData))]
public void TagHelperParseTreeRewriter_CreatesErrorForIncompleteTagHelper(
@ -102,6 +103,128 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
RunParseTreeRewriterTest(documentContent, expectedOutput, new[] { expectedError }, "strong", "p");
}
public static TheoryData<string, MarkupBlock> InvalidHtmlBlockData
{
get
{
var factory = CreateDefaultSpanFactory();
var blockFactory = new BlockFactory(factory);
var dateTimeNow = new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace));
return new TheoryData<string, MarkupBlock>
{
{
"<<<p>>></p>",
new MarkupBlock(
blockFactory.MarkupTagBlock("<"),
blockFactory.MarkupTagBlock("<"),
new MarkupTagHelperBlock("p",
factory.Markup(">>")))
},
{
"<<p />",
new MarkupBlock(
blockFactory.MarkupTagBlock("<"),
new MarkupTagHelperBlock("p"))
},
{
"< p />",
new MarkupBlock(
blockFactory.MarkupTagBlock("< p />"))
},
{
"<input <p />",
new MarkupBlock(
blockFactory.MarkupTagBlock("<input "),
new MarkupTagHelperBlock("p"))
},
{
"< class=\"foo\" <p />",
new MarkupBlock(
new MarkupTagBlock(
factory.Markup("<"),
new MarkupBlock(
new AttributeBlockCodeGenerator(
name: "class",
prefix: new LocationTagged<string>(" class=\"", 1, 0, 1),
suffix: new LocationTagged<string>("\"", 12, 0, 12)),
factory.Markup(" class=\"").With(SpanCodeGenerator.Null),
factory.Markup("foo").With(new LiteralAttributeCodeGenerator(
prefix: new LocationTagged<string>(string.Empty, 9, 0, 9),
value: new LocationTagged<string>("foo", 9, 0, 9))),
factory.Markup("\"").With(SpanCodeGenerator.Null)),
factory.Markup(" ")),
new MarkupTagHelperBlock("p"))
},
{
"</<<p>/></p>>",
new MarkupBlock(
blockFactory.MarkupTagBlock("</"),
blockFactory.MarkupTagBlock("<"),
new MarkupTagHelperBlock("p",
factory.Markup("/>")),
factory.Markup(">"))
},
{
"</<<p>/><strong></p>>",
new MarkupBlock(
blockFactory.MarkupTagBlock("</"),
blockFactory.MarkupTagBlock("<"),
new MarkupTagHelperBlock("p",
factory.Markup("/>"),
blockFactory.MarkupTagBlock("<strong>")),
factory.Markup(">"))
},
{
"</<<p>@DateTime.Now/><strong></p>>",
new MarkupBlock(
blockFactory.MarkupTagBlock("</"),
blockFactory.MarkupTagBlock("<"),
new MarkupTagHelperBlock("p",
dateTimeNow,
factory.Markup("/>"),
blockFactory.MarkupTagBlock("<strong>")),
factory.Markup(">"))
},
{
"</ /< ><p>@DateTime.Now / ><strong></p></ >",
new MarkupBlock(
blockFactory.MarkupTagBlock("</ "),
factory.Markup("/"),
blockFactory.MarkupTagBlock("< >"),
new MarkupTagHelperBlock("p",
dateTimeNow,
factory.Markup(" / >"),
blockFactory.MarkupTagBlock("<strong>")),
blockFactory.MarkupTagBlock("</ >"))
},
{
"<p>< @DateTime.Now ></ @DateTime.Now ></p>",
new MarkupBlock(
new MarkupTagHelperBlock("p",
new MarkupTagBlock(
factory.Markup("< "),
dateTimeNow,
factory.Markup(" >")),
blockFactory.MarkupTagBlock("</ "),
dateTimeNow,
factory.Markup(" >")))
}
};
}
}
[Theory]
[MemberData(nameof(InvalidHtmlBlockData))]
public void TagHelperParseTreeRewriter_AllowsInvalidHtml(string documentContent, MarkupBlock expectedOutput)
{
RunParseTreeRewriterTest(documentContent, expectedOutput, "p");
}
public static IEnumerable<object[]> TextTagsBlockData
{
get