Embed go exp package requirements to ensure we don't use arbitrary exp, move utilities to utils
This commit is contained in:
95
utils/inline/hex.go
Normal file
95
utils/inline/hex.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package inline
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
hextable = "0123456789abcdef"
|
||||
reverseHexTable = "" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
)
|
||||
|
||||
// EncodedLen returns the length of an encoding of n source bytes.
|
||||
// Specifically, it returns n * 2.
|
||||
func EncodedLen(n int) int { return n * 2 }
|
||||
|
||||
// Encode encodes src into [EncodedLen](len(src))
|
||||
// bytes of dst. As a convenience, it returns the number
|
||||
// of bytes written to dst, but this value is always [EncodedLen](len(src)).
|
||||
// Encode implements hexadecimal encoding.
|
||||
func Encode(dst, src []byte) int {
|
||||
j := 0
|
||||
for _, v := range src {
|
||||
dst[j] = hextable[v>>4]
|
||||
dst[j+1] = hextable[v&0x0f]
|
||||
j += 2
|
||||
}
|
||||
return len(src) * 2
|
||||
}
|
||||
|
||||
// ErrLength reports an attempt to decode an odd-length input
|
||||
// using [Decode] or [DecodeString].
|
||||
// The stream-based Decoder returns [io.ErrUnexpectedEOF] instead of ErrLength.
|
||||
var ErrLength = errors.New("encoding/hex: odd length hex string")
|
||||
|
||||
// InvalidByteError values describe errors resulting from an invalid byte in a hex string.
|
||||
type InvalidByteError byte
|
||||
|
||||
func (e InvalidByteError) Error() string {
|
||||
return "encoding/hex: invalid byte"
|
||||
}
|
||||
|
||||
// DecodedLen returns the length of a decoding of x source bytes.
|
||||
// Specifically, it returns x / 2.
|
||||
func DecodedLen(x int) int { return x / 2 }
|
||||
|
||||
// Decode decodes src into [DecodedLen](len(src)) bytes,
|
||||
// returning the actual number of bytes written to dst.
|
||||
//
|
||||
// Decode expects that src contains only hexadecimal
|
||||
// characters and that src has even length.
|
||||
// If the input is malformed, Decode returns the number
|
||||
// of bytes decoded before the error.
|
||||
func Decode(dst, src []byte) (int, error) {
|
||||
i, j := 0, 1
|
||||
for ; j < len(src); j += 2 {
|
||||
p := src[j-1]
|
||||
q := src[j]
|
||||
|
||||
a := reverseHexTable[p]
|
||||
b := reverseHexTable[q]
|
||||
if a > 0x0f {
|
||||
return i, InvalidByteError(p)
|
||||
}
|
||||
if b > 0x0f {
|
||||
return i, InvalidByteError(q)
|
||||
}
|
||||
dst[i] = (a << 4) | b
|
||||
i++
|
||||
}
|
||||
if len(src)%2 == 1 {
|
||||
// Check for invalid char before reporting bad length,
|
||||
// since the invalid char (if present) is an earlier problem.
|
||||
if reverseHexTable[src[j-1]] > 0x0f {
|
||||
return i, InvalidByteError(src[j-1])
|
||||
}
|
||||
return i, ErrLength
|
||||
}
|
||||
return i, nil
|
||||
}
|
234
utils/inline/mime.go
Normal file
234
utils/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
|
||||
}
|
||||
}
|
19
utils/unix.go
Normal file
19
utils/unix.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package utils
|
||||
|
||||
import "net/http"
|
||||
|
||||
// UnixRoundTripper https://github.com/oauth2-proxy/oauth2-proxy/blob/master/pkg/upstream/http.go#L124
|
||||
type UnixRoundTripper struct {
|
||||
Transport *http.Transport
|
||||
}
|
||||
|
||||
// RoundTrip set bare minimum stuff
|
||||
func (t UnixRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req = req.Clone(req.Context())
|
||||
if req.Host == "" {
|
||||
req.Host = "localhost"
|
||||
}
|
||||
req.URL.Host = req.Host // proxy error: no Host in request URL
|
||||
req.URL.Scheme = "http" // make http.Transport happy and avoid an infinite recursion
|
||||
return t.Transport.RoundTrip(req)
|
||||
}
|
Reference in New Issue
Block a user