encoding.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. package response
  4. import (
  5. "slices"
  6. "strconv"
  7. "strings"
  8. )
  9. type acceptEncodingParser struct {
  10. // accepted contains all encoding that particular parser instance advertises.
  11. accepted []string
  12. }
  13. // AcceptEncoding creates parser instance for "Accept-Encoding" header values.
  14. // It accepts list of encodings recognized by user of this parser instance.
  15. func AcceptEncoding(accepted ...string) *acceptEncodingParser {
  16. return &acceptEncodingParser{accepted: accepted}
  17. }
  18. // Parse parses input string according to [HTTP Semantics]
  19. // and returns first encoding that can be understood by us.
  20. //
  21. // Currently this function ignores set weights other than q=0.
  22. // Encodings with q=0 will not be considered.
  23. //
  24. // If string is empty or no encoding was accepted function returns "identity".
  25. //
  26. // For "identity;q=0" and "*;q=0" function returns an empty string. In that case,
  27. // if no other encoding was accepted, 406 Not Acceptable should be returned.
  28. //
  29. // [HTTP Semantics]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept-Encoding.
  30. func (p *acceptEncodingParser) Parse(acceptEncoding string) string {
  31. accepted := "identity"
  32. for enc := range strings.SplitSeq(acceptEncoding, ",") {
  33. enc = strings.TrimSpace(enc)
  34. if qi := strings.IndexByte(enc, ';'); qi > -1 {
  35. qstr := strings.TrimPrefix(enc[qi:], ";")
  36. qstr = strings.TrimSpace(qstr)
  37. qstr = strings.TrimPrefix(qstr, "q=")
  38. q, err := strconv.ParseFloat(qstr, 64)
  39. if err != nil {
  40. continue // Ignore weird float values.
  41. }
  42. enc = strings.TrimSpace(enc[:qi])
  43. if q == 0 && slices.Contains([]string{"identity", "*"}, enc) {
  44. accepted = "" // Explicitly disabled, so can't be used as fallback.
  45. continue
  46. }
  47. if q == 0 {
  48. continue // Skipping unwanted.
  49. }
  50. }
  51. if !slices.Contains(p.accepted, enc) {
  52. continue // Skipping unsupported.
  53. }
  54. accepted = enc
  55. break
  56. }
  57. return accepted
  58. }