headermap.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // Copyright 2025 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package httpcommon
  5. import (
  6. "net/textproto"
  7. "sync"
  8. )
  9. var (
  10. commonBuildOnce sync.Once
  11. commonLowerHeader map[string]string // Go-Canonical-Case -> lower-case
  12. commonCanonHeader map[string]string // lower-case -> Go-Canonical-Case
  13. )
  14. func buildCommonHeaderMapsOnce() {
  15. commonBuildOnce.Do(buildCommonHeaderMaps)
  16. }
  17. func buildCommonHeaderMaps() {
  18. common := []string{
  19. "accept",
  20. "accept-charset",
  21. "accept-encoding",
  22. "accept-language",
  23. "accept-ranges",
  24. "age",
  25. "access-control-allow-credentials",
  26. "access-control-allow-headers",
  27. "access-control-allow-methods",
  28. "access-control-allow-origin",
  29. "access-control-expose-headers",
  30. "access-control-max-age",
  31. "access-control-request-headers",
  32. "access-control-request-method",
  33. "allow",
  34. "authorization",
  35. "cache-control",
  36. "content-disposition",
  37. "content-encoding",
  38. "content-language",
  39. "content-length",
  40. "content-location",
  41. "content-range",
  42. "content-type",
  43. "cookie",
  44. "date",
  45. "etag",
  46. "expect",
  47. "expires",
  48. "from",
  49. "host",
  50. "if-match",
  51. "if-modified-since",
  52. "if-none-match",
  53. "if-unmodified-since",
  54. "last-modified",
  55. "link",
  56. "location",
  57. "max-forwards",
  58. "origin",
  59. "proxy-authenticate",
  60. "proxy-authorization",
  61. "range",
  62. "referer",
  63. "refresh",
  64. "retry-after",
  65. "server",
  66. "set-cookie",
  67. "strict-transport-security",
  68. "trailer",
  69. "transfer-encoding",
  70. "user-agent",
  71. "vary",
  72. "via",
  73. "www-authenticate",
  74. "x-forwarded-for",
  75. "x-forwarded-proto",
  76. }
  77. commonLowerHeader = make(map[string]string, len(common))
  78. commonCanonHeader = make(map[string]string, len(common))
  79. for _, v := range common {
  80. chk := textproto.CanonicalMIMEHeaderKey(v)
  81. commonLowerHeader[chk] = v
  82. commonCanonHeader[v] = chk
  83. }
  84. }
  85. // LowerHeader returns the lowercase form of a header name,
  86. // used on the wire for HTTP/2 and HTTP/3 requests.
  87. func LowerHeader(v string) (lower string, ascii bool) {
  88. buildCommonHeaderMapsOnce()
  89. if s, ok := commonLowerHeader[v]; ok {
  90. return s, true
  91. }
  92. return asciiToLower(v)
  93. }
  94. // CanonicalHeader canonicalizes a header name. (For example, "host" becomes "Host".)
  95. func CanonicalHeader(v string) string {
  96. buildCommonHeaderMapsOnce()
  97. if s, ok := commonCanonHeader[v]; ok {
  98. return s
  99. }
  100. return textproto.CanonicalMIMEHeaderKey(v)
  101. }
  102. // CachedCanonicalHeader returns the canonical form of a well-known header name.
  103. func CachedCanonicalHeader(v string) (string, bool) {
  104. buildCommonHeaderMapsOnce()
  105. s, ok := commonCanonHeader[v]
  106. return s, ok
  107. }