Closer file structure to desired
This commit is contained in:
234
lib/challenge/inline/mime.go
Normal file
234
lib/challenge/inline/mime.go
Normal file
@@ -0,0 +1,234 @@
|
||||
package inline
|
||||
|
||||
// from textproto
|
||||
|
||||
// A MIMEHeader represents a MIME-style header mapping
|
||||
// keys to sets of values.
|
||||
type MIMEHeader map[string][]string
|
||||
|
||||
// Add adds the key, value pair to the header.
|
||||
// It appends to any existing values associated with key.
|
||||
func (h MIMEHeader) Add(key, value string) {
|
||||
key = CanonicalMIMEHeaderKey(key)
|
||||
h[key] = append(h[key], value)
|
||||
}
|
||||
|
||||
// Set sets the header entries associated with key to
|
||||
// the single element value. It replaces any existing
|
||||
// values associated with key.
|
||||
func (h MIMEHeader) Set(key, value string) {
|
||||
h[CanonicalMIMEHeaderKey(key)] = []string{value}
|
||||
}
|
||||
|
||||
// Get gets the first value associated with the given key.
|
||||
// It is case insensitive; [CanonicalMIMEHeaderKey] is used
|
||||
// to canonicalize the provided key.
|
||||
// If there are no values associated with the key, Get returns "".
|
||||
// To use non-canonical keys, access the map directly.
|
||||
func (h MIMEHeader) Get(key string) string {
|
||||
if h == nil {
|
||||
return ""
|
||||
}
|
||||
v := h[CanonicalMIMEHeaderKey(key)]
|
||||
if len(v) == 0 {
|
||||
return ""
|
||||
}
|
||||
return v[0]
|
||||
}
|
||||
|
||||
// Values returns all values associated with the given key.
|
||||
// It is case insensitive; [CanonicalMIMEHeaderKey] is
|
||||
// used to canonicalize the provided key. To use non-canonical
|
||||
// keys, access the map directly.
|
||||
// The returned slice is not a copy.
|
||||
func (h MIMEHeader) Values(key string) []string {
|
||||
if h == nil {
|
||||
return nil
|
||||
}
|
||||
return h[CanonicalMIMEHeaderKey(key)]
|
||||
}
|
||||
|
||||
// Del deletes the values associated with key.
|
||||
func (h MIMEHeader) Del(key string) {
|
||||
delete(h, CanonicalMIMEHeaderKey(key))
|
||||
}
|
||||
|
||||
// CanonicalMIMEHeaderKey returns the canonical format of the
|
||||
// MIME header key s. The canonicalization converts the first
|
||||
// letter and any letter following a hyphen to upper case;
|
||||
// the rest are converted to lowercase. For example, the
|
||||
// canonical key for "accept-encoding" is "Accept-Encoding".
|
||||
// MIME header keys are assumed to be ASCII only.
|
||||
// If s contains a space or invalid header field bytes, it is
|
||||
// returned without modifications.
|
||||
func CanonicalMIMEHeaderKey(s string) string {
|
||||
// Quick check for canonical encoding.
|
||||
upper := true
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if !validHeaderFieldByte(c) {
|
||||
return s
|
||||
}
|
||||
if upper && 'a' <= c && c <= 'z' {
|
||||
s, _ = canonicalMIMEHeaderKey([]byte(s))
|
||||
return s
|
||||
}
|
||||
if !upper && 'A' <= c && c <= 'Z' {
|
||||
s, _ = canonicalMIMEHeaderKey([]byte(s))
|
||||
return s
|
||||
}
|
||||
upper = c == '-'
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
const toLower = 'a' - 'A'
|
||||
|
||||
// validHeaderFieldByte reports whether c is a valid byte in a header
|
||||
// field name. RFC 7230 says:
|
||||
//
|
||||
// header-field = field-name ":" OWS field-value OWS
|
||||
// field-name = token
|
||||
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
|
||||
// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
|
||||
// token = 1*tchar
|
||||
func validHeaderFieldByte(c byte) bool {
|
||||
// mask is a 128-bit bitmap with 1s for allowed bytes,
|
||||
// so that the byte c can be tested with a shift and an and.
|
||||
// If c >= 128, then 1<<c and 1<<(c-64) will both be zero,
|
||||
// and this function will return false.
|
||||
const mask = 0 |
|
||||
(1<<(10)-1)<<'0' |
|
||||
(1<<(26)-1)<<'a' |
|
||||
(1<<(26)-1)<<'A' |
|
||||
1<<'!' |
|
||||
1<<'#' |
|
||||
1<<'$' |
|
||||
1<<'%' |
|
||||
1<<'&' |
|
||||
1<<'\'' |
|
||||
1<<'*' |
|
||||
1<<'+' |
|
||||
1<<'-' |
|
||||
1<<'.' |
|
||||
1<<'^' |
|
||||
1<<'_' |
|
||||
1<<'`' |
|
||||
1<<'|' |
|
||||
1<<'~'
|
||||
return ((uint64(1)<<c)&(mask&(1<<64-1)) |
|
||||
(uint64(1)<<(c-64))&(mask>>64)) != 0
|
||||
}
|
||||
|
||||
// canonicalMIMEHeaderKey is like CanonicalMIMEHeaderKey but is
|
||||
// allowed to mutate the provided byte slice before returning the
|
||||
// string.
|
||||
//
|
||||
// For invalid inputs (if a contains spaces or non-token bytes), a
|
||||
// is unchanged and a string copy is returned.
|
||||
//
|
||||
// ok is true if the header key contains only valid characters and spaces.
|
||||
// ReadMIMEHeader accepts header keys containing spaces, but does not
|
||||
// canonicalize them.
|
||||
func canonicalMIMEHeaderKey(a []byte) (_ string, ok bool) {
|
||||
if len(a) == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// See if a looks like a header key. If not, return it unchanged.
|
||||
noCanon := false
|
||||
for _, c := range a {
|
||||
if validHeaderFieldByte(c) {
|
||||
continue
|
||||
}
|
||||
// Don't canonicalize.
|
||||
if c == ' ' {
|
||||
// We accept invalid headers with a space before the
|
||||
// colon, but must not canonicalize them.
|
||||
// See https://go.dev/issue/34540.
|
||||
noCanon = true
|
||||
continue
|
||||
}
|
||||
return string(a), false
|
||||
}
|
||||
if noCanon {
|
||||
return string(a), true
|
||||
}
|
||||
|
||||
upper := true
|
||||
for i, c := range a {
|
||||
// Canonicalize: first letter upper case
|
||||
// and upper case after each dash.
|
||||
// (Host, User-Agent, If-Modified-Since).
|
||||
// MIME headers are ASCII only, so no Unicode issues.
|
||||
if upper && 'a' <= c && c <= 'z' {
|
||||
c -= toLower
|
||||
} else if !upper && 'A' <= c && c <= 'Z' {
|
||||
c += toLower
|
||||
}
|
||||
a[i] = c
|
||||
upper = c == '-' // for next time
|
||||
}
|
||||
|
||||
// The compiler recognizes m[string(byteSlice)] as a special
|
||||
// case, so a copy of a's bytes into a new string does not
|
||||
// happen in this map lookup:
|
||||
if v := commonHeader[string(a)]; v != "" {
|
||||
return v, true
|
||||
}
|
||||
return string(a), true
|
||||
}
|
||||
|
||||
func init() {
|
||||
initCommonHeader()
|
||||
}
|
||||
|
||||
// commonHeader interns common header strings.
|
||||
var commonHeader map[string]string
|
||||
|
||||
func initCommonHeader() {
|
||||
commonHeader = make(map[string]string)
|
||||
for _, v := range []string{
|
||||
"Accept",
|
||||
"Accept-Charset",
|
||||
"Accept-Encoding",
|
||||
"Accept-Language",
|
||||
"Accept-Ranges",
|
||||
"Cache-Control",
|
||||
"Cc",
|
||||
"Connection",
|
||||
"Content-Id",
|
||||
"Content-Language",
|
||||
"Content-Length",
|
||||
"Content-Transfer-Encoding",
|
||||
"Content-Type",
|
||||
"Cookie",
|
||||
"Date",
|
||||
"Dkim-Signature",
|
||||
"Etag",
|
||||
"Expires",
|
||||
"From",
|
||||
"Host",
|
||||
"If-Modified-Since",
|
||||
"If-None-Match",
|
||||
"In-Reply-To",
|
||||
"Last-Modified",
|
||||
"Location",
|
||||
"Message-Id",
|
||||
"Mime-Version",
|
||||
"Pragma",
|
||||
"Received",
|
||||
"Return-Path",
|
||||
"Server",
|
||||
"Set-Cookie",
|
||||
"Subject",
|
||||
"To",
|
||||
"User-Agent",
|
||||
"Via",
|
||||
"X-Forwarded-For",
|
||||
"X-Imforwards",
|
||||
"X-Powered-By",
|
||||
} {
|
||||
commonHeader[v] = v
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user