go-premailer icon indicating copy to clipboard operation
go-premailer copied to clipboard

Premailer is escaping URLs not only in html attributes, but in a content as well.

Open erudenko opened this issue 9 months ago • 5 comments

Hello,

First of all, thank you for this library.

It works like a charm, exceptfor one little thing.

<!DOCTYPE html><html><head>
	 <style>
	   p { color: red; font-size: 14px; }
	   .header { background-color: blue; }
	 </style>
</head>
<body>
	 <p>This is a test paragraph</p>
	 <a href="https://example.com?a=1&b=2">
			https://example.com?a=1&b=2
	 </a>


</body></html>

Herer you can see the same URL in two places, one in a href attribute and another one is a content of a tag.

After premailer does its job, both of them are escaped like: https://example.com?a=1&apm;b=2

Whether the href case is correct, it is safer to escape URL in attributes, the text thing is incorrect as text should be treated as is.

erudenko avatar Apr 14 '25 03:04 erudenko

Hi @erudenko Thanks for reporting.

This package uses other packages to parse and query css rules. It does never touch those values itself. Since the parsing to dom and converting back to html causes some problem (see also https://github.com/vanng822/go-premailer/issues/15).

I would guess the source of the problem is down to net/html

If you have time please investigate and see if github.com/PuerkitoBio/goquery can do something

vanng822 avatar May 02 '25 07:05 vanng822

The escape is in this function of net/html

func render1(w writer, n *Node) error {
	// Render non-element nodes; these are the easy cases.
	switch n.Type {
	case ErrorNode:
		return errors.New("html: cannot render an ErrorNode node")
	case TextNode:
		return escape(w, n.Data)
	case DocumentNode:
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			if err := render1(w, c); err != nil {
				return err
			}
		}
		return nil
	case ElementNode:
		// No-op.
	case CommentNode:

I found a way to not use the escape but now the question is: Did you really have problem with &amp; What mail reader do you have problem with rendering of this link text? Browsers should work fine?

vanng822 avatar Jun 28 '25 21:06 vanng822

Chrome, Firefox and Safari looks like this

Image

vanng822 avatar Jun 28 '25 21:06 vanng822

The workaround is simple transverse through all nodes and whenever you find a TextNode make it RawNode then render1 will render as it is but this can be a security concern.

So I won't introduce workaround unless you show me some examples of mail readers out there that have rendering problem.

vanng822 avatar Jun 28 '25 21:06 vanng822

EDITED: My bad, Ignore all bellow. You can't change the Type TextNode before calling since Premailer needs it for collecting css rules. You could do it by calling Transform one, Change Type of TextNode and call Transform again but that is bad to do so.

~~I just realized that you actually can easily do the workaround yourself so maybe I just add an example how-to and not introduce it.~~ 

~~You parse html string to dom and then make all the text node you want. Here you can have your logic to control exact node you want to make it unsafe by change the Type to RawNode....~~

vanng822 avatar Jun 28 '25 21:06 vanng822