84 lines
2.3 KiB
Go
84 lines
2.3 KiB
Go
package http
|
|
|
|
import (
|
|
"net/url"
|
|
sh "serveg/internal/string_helper"
|
|
"strings"
|
|
)
|
|
|
|
const HeaderTimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
|
|
|
|
// search in splitted parts of header value
|
|
func HeaderValueContains(sourceSplit []string, target string) bool {
|
|
for _, v := range sourceSplit {
|
|
v = strings.TrimSpace(v)
|
|
if strings.EqualFold(v, target) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// ContentDisposition builds a Content-Disposition header value (RFC 6266).
|
|
// dispositionType is "inline" or "attachment".
|
|
// filename is an ASCII fallback for old clients,
|
|
// filename* is the exact UTF-8 name.
|
|
//
|
|
// ContentDisposition("inline", "отчёт 1.txt") ->
|
|
// inline; filename="_____ 1.txt"; filename*=UTF-8''%D0%BE%D1%82%D1%87%D1%91%D1%82%201.txt
|
|
func ContentDisposition(dispositionType, fileName string) string {
|
|
var sb sh.StringBuilder
|
|
sb.Grow(len(dispositionType) + len(fileName)*4 + 32)
|
|
sb.AddS(dispositionType)
|
|
sb.AddS(`; filename="`).AddS(AsciiFallbackName(fileName)).AddB('"')
|
|
sb.AddS(`; filename*=UTF-8''`).AddS(PercentEncodeHeaderValue(fileName))
|
|
return sb.StringUnsafe()
|
|
}
|
|
|
|
// percent-encodes characters that are not allowed in urls
|
|
func PercentEcodeUrl(p string) string {
|
|
u := url.URL{Path: p}
|
|
return u.EscapedPath()
|
|
}
|
|
|
|
// PercentEncodeHeaderValue percent-encodes characters that are not allowed in header values
|
|
func PercentEncodeHeaderValue(s string) string {
|
|
const hexDigits = "0123456789ABCDEF"
|
|
var sb sh.StringBuilder
|
|
sb.Grow(len(s))
|
|
for i := 0; i < len(s); i++ {
|
|
c := s[i]
|
|
if isAttrChar(c) {
|
|
sb.AddB(c)
|
|
} else {
|
|
sb.AddB('%').AddB(hexDigits[c>>4]).AddB(hexDigits[c&0x0F])
|
|
}
|
|
}
|
|
return sb.StringUnsafe()
|
|
}
|
|
|
|
// attr-char = ALPHA / DIGIT / "!" / "#" / "$" / "&" / "+" / "-" / "."
|
|
// / "^" / "_" / "`" / "|" / "~"
|
|
func isAttrChar(c byte) bool {
|
|
switch {
|
|
case 'a' <= c && c <= 'z', 'A' <= c && c <= 'Z', '0' <= c && c <= '9':
|
|
return true
|
|
}
|
|
return strings.IndexByte("!#$&+-.^_`|~", c) >= 0
|
|
}
|
|
|
|
// AsciiFallbackName replaces each character that can't be safely put
|
|
// in a quoted-string with '_'. One '_' per character, not per byte.
|
|
func AsciiFallbackName(s string) string {
|
|
var sb sh.StringBuilder
|
|
sb.Grow(len(s))
|
|
// range over string iterates runes, invalid UTF-8 gives utf8.RuneError
|
|
for _, r := range s {
|
|
if r < 0x20 || r >= 0x7F || r == '"' || r == '\\' || r == '%' {
|
|
r = '_'
|
|
}
|
|
sb.AddB(byte(r))
|
|
}
|
|
return sb.StringUnsafe()
|
|
}
|