109 lines
2.8 KiB
Go
109 lines
2.8 KiB
Go
package http
|
|
|
|
import (
|
|
"net/url"
|
|
sh "serveg/internal/string_helper"
|
|
"strings"
|
|
)
|
|
|
|
const HeaderTimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
|
|
|
|
type SetStr map[string]struct{}
|
|
|
|
var SecretHeaders = SetStr{
|
|
"authorization": {},
|
|
}
|
|
|
|
func HeadersToString(headers HeadersMap, secretHeaders SetStr) string {
|
|
sb := sh.StringBuilder{Buf: make([]byte, 0, len(headers)*64)}
|
|
sb.AddS("{ ")
|
|
for k, v := range headers {
|
|
sb.AddB('"').AddS(k).AddS(`": "`)
|
|
if _, ok := secretHeaders[k]; ok {
|
|
sb.AddS("***")
|
|
} else {
|
|
sb.AddS(v)
|
|
}
|
|
sb.AddS(`", `)
|
|
}
|
|
if sb.Len() > 2 {
|
|
sb.Remove(2)
|
|
}
|
|
sb.AddS(" }")
|
|
return sb.StringUnsafe()
|
|
}
|
|
|
|
// 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()
|
|
}
|