Exemple #1
0
        /// <summary>Invokes the CSS parser on the element.</summary>
        /// <param name="node">The <see cref="HtmlNode"/> to scan.</param>
        /// <param name="parentNode">The parent of the node.</param>
        /// <returns><see langword="true"/> if processing ended with no exceptions.</returns>
        private bool ProcessStyleTag(HtmlNode node, HtmlNode parentNode)
        {
            var styleScanner = new CssScanner(Policy);

            try
            {
                CleanResults cleanStyleSheet = styleScanner.ScanStyleSheet(node.FirstChild.InnerHtml);
                errorMessages.AddRange(cleanStyleSheet.GetErrorMessages());

                /*
                 * If IE gets an empty style tag, i.e. <style/> it will break all CSS on the page. I wish I
                 * was kidding. So, if after validation no CSS properties are left, we would normally be left
                 * with an empty style tag and break all CSS. To prevent that, we have this check.
                 */
                string cleanHtml = cleanStyleSheet.GetCleanHtml();
                node.FirstChild.InnerHtml = string.IsNullOrEmpty(cleanHtml) ? EMPTY_CSS_COMMENT : cleanHtml;
            }
            catch (Exception exc)
            {
                if (exc is ScanException || exc is ParseException)
                {
                    AddError(Constants.ERROR_CSS_TAG_MALFORMED, HtmlEntityEncoder.HtmlEntityEncode(node.FirstChild.InnerHtml));

                    parentNode.RemoveChild(node);
                    return(false);
                }
                else
                {
                    throw;
                }
            }

            return(true);
        }
Exemple #2
0
        private bool ProcessAttributes(HtmlNode node, Tag tag)
        {
            string tagName = tag.Name;
            int    currentAttributeIndex = 0;

            while (currentAttributeIndex < node.Attributes.Count)
            {
                HtmlAttribute htmlAttribute = node.Attributes[currentAttributeIndex];
                string        name          = htmlAttribute.Name;
                string        value         = htmlAttribute.Value;
                Attribute     attribute     = tag.GetAttributeByName(name);

                if (attribute == null)
                {
                    attribute = Policy.GetGlobalAttributeByName(name);

                    // Not a global attribute, perhaps it is a dynamic attribute, if allowed.
                    if (attribute == null && Policy.AllowsDynamicAttributes)
                    {
                        attribute = Policy.GetDynamicAttributeByName(name);
                    }
                }

                if (name.ToLowerInvariant() == "style" && attribute != null)
                {
                    var styleScanner = new CssScanner(Policy);

                    try
                    {
                        CleanResults cleanInlineStyle = styleScanner.ScanInlineStyle(value, tagName);
                        htmlAttribute.Value = cleanInlineStyle.GetCleanHtml();
                        errorMessages.AddRange(cleanInlineStyle.GetErrorMessages());
                    }
                    catch (Exception exc)
                    {
                        if (exc is ScanException || exc is ParseException)
                        {
                            AddError(Constants.ERROR_CSS_ATTRIBUTE_MALFORMED,
                                     HtmlEntityEncoder.HtmlEntityEncode(value), HtmlEntityEncoder.HtmlEntityEncode(tagName));

                            node.Attributes.Remove(name);
                            currentAttributeIndex--;
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
                else
                {
                    if (attribute != null)
                    {
                        value = HtmlEntity.DeEntitize(value);
                        string lowerCaseValue = value.ToLowerInvariant();

                        bool isAttributeValid = attribute.AllowedValues.Any(v => v != null && v.ToLowerInvariant() == lowerCaseValue) ||
                                                attribute.AllowedRegExp.Any(r => r != null && Regex.IsMatch(value, "^" + r + "$"));

                        if (!isAttributeValid)
                        {
                            string onInvalidAction = attribute.OnInvalid;
                            if (onInvalidAction == "removeTag")
                            {
                                RemoveNode(node);
                                AddError(Constants.ERROR_ATTRIBUTE_INVALID_REMOVED,
                                         HtmlEntityEncoder.HtmlEntityEncode(tagName),
                                         HtmlEntityEncoder.HtmlEntityEncode(name),
                                         HtmlEntityEncoder.HtmlEntityEncode(value));
                            }
                            else if (onInvalidAction == "filterTag")
                            {
                                // Remove the node and move up the rest that was inside the tag after processing
                                ProcessChildren(node);
                                PromoteChildren(node);
                                AddError(Constants.ERROR_ATTRIBUTE_CAUSE_FILTER,
                                         HtmlEntityEncoder.HtmlEntityEncode(tagName),
                                         HtmlEntityEncoder.HtmlEntityEncode(name),
                                         HtmlEntityEncoder.HtmlEntityEncode(value));
                            }
                            else if (onInvalidAction == "encodeTag")
                            {
                                // Encode the node and move up the rest that was inside the tag after processing
                                ProcessChildren(node);
                                EncodeAndPromoteChildren(node);
                                AddError(Constants.ERROR_ATTRIBUTE_CAUSE_ENCODE,
                                         HtmlEntityEncoder.HtmlEntityEncode(tagName),
                                         HtmlEntityEncoder.HtmlEntityEncode(name),
                                         HtmlEntityEncoder.HtmlEntityEncode(value));
                            }
                            else
                            {
                                // Just remove the attribute
                                node.Attributes.Remove(attribute.Name);
                                currentAttributeIndex--;
                                AddError(Constants.ERROR_ATTRIBUTE_INVALID,
                                         HtmlEntityEncoder.HtmlEntityEncode(tagName),
                                         HtmlEntityEncoder.HtmlEntityEncode(name),
                                         HtmlEntityEncoder.HtmlEntityEncode(value));
                            }

                            if (new string[] { "removeTag", "filterTag", "encodeTag" }.Contains(onInvalidAction))
                            {
                                return(false); // Can't process any more if we remove/filter/encode the tag
                            }
                        }
                    }
                    else
                    {
                        AddError(Constants.ERROR_ATTRIBUTE_NOT_IN_POLICY,
                                 HtmlEntityEncoder.HtmlEntityEncode(tagName),
                                 HtmlEntityEncoder.HtmlEntityEncode(name),
                                 HtmlEntityEncoder.HtmlEntityEncode(value));
                        node.Attributes.Remove(name);
                        currentAttributeIndex--;
                    }
                }

                currentAttributeIndex++;
            }

            return(true);
        }