| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 |
- // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
- // SPDX-License-Identifier: Apache-2.0
- package response
- import (
- "slices"
- "strconv"
- "strings"
- )
- type acceptEncodingParser struct {
- // accepted contains all encoding that particular parser instance advertises.
- accepted []string
- }
- // AcceptEncoding creates parser instance for "Accept-Encoding" header values.
- // It accepts list of encodings recognized by user of this parser instance.
- func AcceptEncoding(accepted ...string) *acceptEncodingParser {
- return &acceptEncodingParser{accepted: accepted}
- }
- // Parse the input string according to [HTTP Semantics] and return our
- // most-preferred encoding that the client accepts. Candidates are matched in
- // the order of the accepted list passed to [AcceptEncoding], so the server's
- // preference wins over the order (and weights) the client advertises.
- //
- // Currently this function ignores set weights other than q=0.
- // Encodings with q=0 will not be considered.
- //
- // Returns "identity" if the input is empty or no accepted encoding matches.
- //
- // [HTTP Semantics]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept-Encoding.
- func (p *acceptEncodingParser) Parse(acceptEncoding string) string {
- // bestIdx tracks the lowest index into p.accepted (i.e. the server's most
- // preferred encoding) seen so far. Tracking it inline avoids collecting the
- // client's encodings into a slice, keeping this method allocation free.
- bestIdx := -1
- for enc := range strings.SplitSeq(acceptEncoding, ",") {
- enc = strings.TrimSpace(enc)
- if qi := strings.IndexByte(enc, ';'); qi > -1 {
- qstr := strings.TrimPrefix(enc[qi:], ";")
- qstr = strings.TrimSpace(qstr)
- qstr = strings.TrimPrefix(qstr, "q=")
- q, err := strconv.ParseFloat(qstr, 64)
- if err != nil || q == 0 {
- continue // Ignore weird float values.
- }
- enc = strings.TrimSpace(enc[:qi])
- }
- if i := slices.Index(p.accepted, enc); i > -1 && (bestIdx == -1 || i < bestIdx) {
- bestIdx = i
- if bestIdx == 0 {
- break // Nothing can beat the top server preference.
- }
- }
- }
- if bestIdx == -1 {
- return "identity"
- }
- return p.accepted[bestIdx]
- }
|