headermap.go raw

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