dti3914 2016-06-26 10:36
浏览 123
已采纳

防止在模板中转义正斜杠

I'm working on converting a pet project of mine from Python to Go just to help me get a bit familiar with the language. An issue I am currently facing is that it's escaping my forward slashes. So it will receive a string like:

/location/to/something

and it then becomes

%2flocation%2fto%2fsomething

Now, it's only doing this when it's in a link (from what I've been reading this escaping is contextual) so this is what the line in the HTML template looks like:

<tr><td><a href="/file?file={{.FullFilePath}}">{{.FileName}}</a></td></tr>

If possible, how can I prevent this in either the template or the code itself?

This is what my templating function looks like (yes, I know it's hackish)

func renderTemplate(w http.ResponseWriter, tmpl string) {
    t, err := template.ParseFiles(templates_dir+"base.html", templates_dir+tmpl)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    if tmpl == "view.html" {
        err = t.Execute(w, FileList)
    } else {
        err = t.Execute(w, nil)
    }
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}
  • 写回答

2条回答 默认 最新

  • dtgv52982 2016-06-26 11:45
    关注

    As the value of .FullFilePath, pass a value of type template.URL instead of string, which will tell the html/template package not to escape it.

    For example:

    func main() {
        t := template.Must(template.New("").Parse(templ))
    
        m := map[string]interface{}{
            "FileName":     "something.txt",
            "FileFullPath": template.URL("/location/to/something"),
        }
    
        if err := t.Execute(os.Stdout, m); err != nil {
            panic(err)
        }
    }
    
    const templ = `<tr><td><a href="/file?file={{.FileFullPath}}">{{.FileName}}</a></td></tr>`
    

    Output (try it on the Go Playground):

    <tr><td><a href="/file?file=/location/to/something">something.txt</a></td></tr>
    

    Note that even though forward slashes / are allowed in URLs, the reason why the template package still encodes them is because it analyses the URL and sees that the value you want to include is the value of a URL parameter (file=XXX), and so it also encodes the slashes (so that everything you pass in will be part of the value of the file URL parameter).

    If you plan to acquire this file path at the server side from URL parameters, then what the template package does is the correct and proper way.

    But know that by doing this, you'll lose the safety that prevents code injection into URLs. If you're the one providing the values and you know they are safe, there is no problem. But if the data comes from a user input for example, never do this.

    Also note that if you pass the whole URL (and not just a part of it), it will work without using template.URL (try this variant on the Go Playground):

    func main() {
        t := template.Must(template.New("").Parse(templ))
    
        m := map[string]interface{}{
            "FileName": "something.txt",
            "FileURL":  "/file?file=/location/to/something",
        }
    
        if err := t.Execute(os.Stdout, m); err != nil {
            panic(err)
        }
    }
    
    const templ = `<tr><td><a href="{{.FileURL}}">{{.FileName}}</a></td></tr>`
    

    Also note that the recommended way in my opinion would be to include the file path as part of the URL path and not as the value of a parameter, so instead you should create urls like this:

    /file/location/to/something
    

    Map your handler (which serves the file content, see this answer as an example) to the /file/ pattern, and when it is matched and your handler is called, cut off the /file/ prefix from the path r.URL.Path, and the rest will be the full file path. If you choose this, you also won't need the template.URL conversion (because the value you include is not a value of a URL parameter anymore):

    func main() {
        t := template.Must(template.New("").Parse(templ))
    
        m := map[string]interface{}{
            "FileName":     "something.txt",
            "FileFullPath": "/location/to/something",
        }
    
        if err := t.Execute(os.Stdout, m); err != nil {
            panic(err)
        }
    }
    
    const templ = `<tr><td><a href="/file{{.FileFullPath}}">{{.FileName}}</a></td></tr>`
    

    Try this on the Go Playground.

    Also very important: never parse templates in your handler functions! For details see:

    It takes too much time when using "template" package to generate a dynamic web page to client in golang

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 下图接收小电路,谁知道原理
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测
  • ¥15 ETLCloud 处理json多层级问题
  • ¥15 matlab中使用gurobi时报错
  • ¥15 这个主板怎么能扩出一两个sata口
  • ¥15 不是,这到底错哪儿了😭