fork of whitequark.org/git-pages with mods for tangled
at main 2.4 kB view raw
1package git_pages 2 3import ( 4 "cmp" 5 "regexp" 6 "slices" 7 "strconv" 8 "strings" 9) 10 11var httpAcceptEncodingRegexp = regexp.MustCompile(`` + 12 // token optionally prefixed by whitespace 13 `^[ \t]*([a-zA-Z0-9$!#$%&'*+.^_\x60|~-]+)` + 14 // quality value prefixed by a semicolon optionally surrounded by whitespace 15 `(?:[ \t]*;[ \t]*q=(0(?:\.[0-9]{1,3})?|1(?:\.0{1,3})?))?` + 16 // optional whitespace followed by comma or end of line 17 `[ \t]*(?:,|$)`, 18) 19 20type httpEncoding struct { 21 code string 22 qval float64 23} 24 25type httpEncodings struct { 26 encodings []httpEncoding 27} 28 29func parseHTTPEncodings(headerValue string) (result httpEncodings) { 30 for headerValue != "" { 31 matches := httpAcceptEncodingRegexp.FindStringSubmatch(headerValue) 32 if matches == nil { 33 return httpEncodings{} 34 } 35 enc := httpEncoding{strings.ToLower(matches[1]), 1.0} 36 if matches[2] != "" { 37 enc.qval, _ = strconv.ParseFloat(matches[2], 64) 38 } 39 result.encodings = append(result.encodings, enc) 40 headerValue = headerValue[len(matches[0]):] 41 } 42 if len(result.encodings) == 0 { 43 // RFC 9110 says (https://httpwg.org/specs/rfc9110.html#field.accept-encoding): 44 // "If no Accept-Encoding header field is in the request, any content 45 // coding is considered acceptable by the user agent." 46 // In practice, no client expects to receive a compressed response 47 // without having sent Accept-Encoding in the request. 48 } 49 return 50} 51 52// Negotiate returns the most preferred encoding that is acceptable by the 53// client, or an empty string if no encodings are acceptable. 54func (e *httpEncodings) Negotiate(codes ...string) string { 55 prefs := make(map[string]float64, len(codes)) 56 for _, code := range codes { 57 prefs[code] = 0 58 } 59 implicitIdentity := true 60 for _, enc := range e.encodings { 61 if enc.code == "*" { 62 for code := range prefs { 63 prefs[code] = enc.qval 64 } 65 implicitIdentity = false 66 } else if _, ok := prefs[enc.code]; ok { 67 prefs[enc.code] = enc.qval 68 } 69 if enc.code == "*" || enc.code == "identity" { 70 implicitIdentity = false 71 } 72 } 73 if _, ok := prefs["identity"]; ok && implicitIdentity { 74 prefs["identity"] = -1 // sort last 75 } 76 encs := make([]httpEncoding, len(codes)) 77 for idx, code := range codes { 78 encs[idx] = httpEncoding{code, prefs[code]} 79 } 80 slices.SortStableFunc(encs, func(a, b httpEncoding) int { 81 return -cmp.Compare(a.qval, b.qval) 82 }) 83 for _, enc := range encs { 84 if enc.qval != 0 { 85 return enc.code 86 } 87 } 88 return "" 89}