HTML Template may invalidate URLs encoded using url.QueryEscape

I hope am not duplicating another discussion topic.

Context

We use the url package to construct URLs that later get embedded in HTML templates using html/template package.

Problem

URLs with query strings that are encoded with + for space values get escaped in HTML with + that may invalidate the URL.

Example: https://play.golang.org/p/ulzLqByiEX

Question

Am I wrong to believe that the template package should not escape URLs encoded with +?

use template.HTMLEscapeString instead template.HTML :wink:
https://play.golang.org/p/JKMxwOj5TI

Thanks for looking into this George.

I expect my link in the href tag to look like http://goolge.com/?q=hellow+world instead of http://goolge.com/?q=hellow+world. Both template.HTML and template.HTMLEscapeString seem to do the same thing. In fact, we risk double escaping with the latter if you add something like http://google.com/?q=hello+world&bar=eek which will result in http://google.com/?q=hello+world&bar=eek

Hey @emb,

Have a look at this question here.

I wrote the poster an answer which I believe answers this question too :slight_smile:

Here’s my answer to the poster’s question: Html/template still escaping template.URL in <a href>?

Basically, encoding with &#43; is still correct and if you run the following for an example, you’ll see it still takes you to the correct link:

package main

import (
	"fmt"
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		fmt.Fprintln(w, "<a href='http://google.com/?q=hello&#43;world'>hello+world</a>")
	})
	log.Fatal(http.ListenAndServe(":9000", nil))
}
1 Like

Thanks @radovskyb. I did look at that question initially and was convinced by your answer. It works on most browsers, but not necessarily in all HTML Rendering mail clients :stuck_out_tongue: Which is mainly the use case in our team.

Apart from using url.QueryUnescape(string) (string, error) as a work around before passing the string to the template, do you think there a simpler/cleaner solution?

1 Like

Ah ok, I see. Well in that case, I would probably go with using html.UnescapeString, not url.QueryUnescape, especially since for the above example, url.QueryUnescape won’t even turn the &#43; back into a +.

Example:

package main

import (
	"fmt"
	"html"
	"log"
	"net/url"
)

var urlStr = "http://google.com/?q=hello&#43;world"

func main() {
	urlEsc, err := url.QueryUnescape(urlStr)
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println(urlEsc) // http://google.com/?q=hello&#43;world

	fmt.Println(html.UnescapeString(urlStr)) // http://google.com/?q=hello+world
}
2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.