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 oracle集群安装出bug
  • ¥15 关于#python#的问题:自动化测试
  • ¥20 问题请教!vue项目关于Nginx配置nonce安全策略的问题
  • ¥15 教务系统账号被盗号如何追溯设备
  • ¥20 delta降尺度方法,未来数据怎么降尺度
  • ¥15 c# 使用NPOI快速将datatable数据导入excel中指定sheet,要求快速高效
  • ¥15 再不同版本的系统上,TCP传输速度不一致
  • ¥15 高德地图点聚合中Marker的位置无法实时更新
  • ¥15 DIFY API Endpoint 问题。
  • ¥20 sub地址DHCP问题