Запрет экранирования косой черты в шаблонах

Я работаю над преобразованием моего любимого проекта из Python в Go, чтобы помочь мне немного познакомиться с языком. Проблема, с которой я сейчас сталкиваюсь, заключается в том, что она ускользает от моих слэшей. Таким образом, он получит строку вроде:

/location/to/something

и тогда становится

%2flocation%2fto%2fsomething

Теперь он делает это только тогда, когда находится в ссылке (из того, что я читал, экранирование контекстуально), так выглядит строка в шаблоне HTML:

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

Если возможно, как я могу предотвратить это в шаблоне или в самом коде?

Вот так выглядит моя шаблонная функция (да, я знаю, что она хакерская)

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)
    }
}
 icza26 июн. 2016 г., 13:14
 basica26 июн. 2016 г., 13:34
@icza, спасибо, что направили меня по этой ссылке, но я не вижу, как я могу реализовать это решение здесь. По общему признанию, я все еще новичок, так что, возможно, именно поэтому. Я нашел другой вопрос, решение которого помогло мне, поэтому я разместил его здесь.
 icza26 июн. 2016 г., 13:48
Смотрите мой ответ ниже.

Ответы на вопрос(2)

Итак, решение, которое я нашел (и, пожалуйста, опубликуйте, если есть лучшее), основано на ответеВот.

Я изменил структуру, которую я использовал с:

type File struct {
    FullFilePath string
    FileName     string
}

К этому:

type File struct {
    FullFilePath template.HTML
    FileName     string
}

И переместил html в имя FullFilePath, а затем поместил его в template.HTML, чтобы каждое имя FullFilePath, которое я генерировал, было сделано так:

file := File{template.HTML("<a href=\"/file?file=" + path + "\"</a>"), f.Name()}

И моя строка файла шаблона была изменена на это:

<tr><td>{{.FullFilePath}}{{.FileName}}</td></tr>
Решение Вопроса

Как значение.FullFilePathпередать значение типаtemplate.URL вместоstring, который скажетhtml/template Пакет, чтобы не избежать этого.

Например:

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>`

Вывод (попробуйте наGo Playground):

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

Обратите внимание, что даже если косая черта/ разрешены в URL, причина, почемуtemplate Пакет все еще кодирует их, потому что он анализирует URL и видит, что значение, которое вы хотите включить, является значением параметра URL (file=XXX), и поэтому он также кодирует косые черты (так что все, что вы передаете, будет частью значенияfile Параметр URL).

Если вы планируете получить этот путь к файлу на стороне сервера из параметров URL, тоtemplate Пакет делает это правильно и правильно.

Но знайте, что, делая это, вы потеряете безопасность, которая предотвращает внедрение кода в URL. Если вы тот, кто предоставляет значения, и вы знаете, что они безопасны, проблем нет. Но если данные поступают, например, из пользовательского ввода, никогда не делайте этого.

Также обратите внимание, что если вы передадите весь URL (а не только его часть), он будет работать без использованияtemplate.URL (попробуйте этот вариант на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>`

Также обратите внимание, что рекомендуемый способ, на мой взгляд, заключается в том, чтобы включить путь к файлу как часть пути URL, а не как значение параметра, поэтому вместо этого вы должны создать URL-адреса, как это:

/file/location/to/something

Сопоставьте свой обработчик (который обслуживает содержимое файла, см.этот ответ в качестве примера) к/file/ шаблон, и когда он соответствует и ваш обработчик вызывается, отрезать/file/ префикс с путиr.URL.Path, а остальное будет полный путь к файлу. Если вы выберете это, вам также не понадобитсяtemplate.URL преобразование (поскольку значение, которое вы включаете, больше не является значением параметра URL):

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>`

Попробуйте это наGo Playground.

Также очень важно: никогда не анализируйте шаблоны в функциях вашего обработчика! Подробнее см .:

Использование пакета «template» для создания динамической веб-страницы клиенту в golang занимает слишком много времени

 icza26 июн. 2016 г., 14:09
@basica Также смотрите примечание, добавленное в конце: никогда не анализируйте шаблоны в функциях обработчика (это медленно и должно быть сделано до вызова обработчиков).
 basica26 июн. 2016 г., 14:08
Спасибо, это очень ценится. Спасибо за разъяснение рисков безопасности, в моем случае это не применимо (это просто то, что я использую дома, а не публично), но это полезно знать другим.

Ваш ответ на вопрос