metadata.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /*
  2. *
  3. * Copyright 2014 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. // Package metadata define the structure of the metadata supported by gRPC library.
  19. // Please refer to https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md
  20. // for more information about custom-metadata.
  21. package metadata // import "google.golang.org/grpc/metadata"
  22. import (
  23. "context"
  24. "fmt"
  25. "strings"
  26. "google.golang.org/grpc/internal"
  27. )
  28. func init() {
  29. internal.FromOutgoingContextRaw = fromOutgoingContextRaw
  30. }
  31. // DecodeKeyValue returns k, v, nil.
  32. //
  33. // Deprecated: use k and v directly instead.
  34. func DecodeKeyValue(k, v string) (string, string, error) {
  35. return k, v, nil
  36. }
  37. // MD is a mapping from metadata keys to values. Users should use the following
  38. // two convenience functions New and Pairs to generate MD.
  39. type MD map[string][]string
  40. // New creates an MD from a given key-value map.
  41. //
  42. // Only the following ASCII characters are allowed in keys:
  43. // - digits: 0-9
  44. // - uppercase letters: A-Z (normalized to lower)
  45. // - lowercase letters: a-z
  46. // - special characters: -_.
  47. //
  48. // Uppercase letters are automatically converted to lowercase.
  49. //
  50. // Keys beginning with "grpc-" are reserved for grpc-internal use only and may
  51. // result in errors if set in metadata.
  52. func New(m map[string]string) MD {
  53. md := make(MD, len(m))
  54. for k, val := range m {
  55. key := strings.ToLower(k)
  56. md[key] = append(md[key], val)
  57. }
  58. return md
  59. }
  60. // Pairs returns an MD formed by the mapping of key, value ...
  61. // Pairs panics if len(kv) is odd.
  62. //
  63. // Only the following ASCII characters are allowed in keys:
  64. // - digits: 0-9
  65. // - uppercase letters: A-Z (normalized to lower)
  66. // - lowercase letters: a-z
  67. // - special characters: -_.
  68. //
  69. // Uppercase letters are automatically converted to lowercase.
  70. //
  71. // Keys beginning with "grpc-" are reserved for grpc-internal use only and may
  72. // result in errors if set in metadata.
  73. func Pairs(kv ...string) MD {
  74. if len(kv)%2 == 1 {
  75. panic(fmt.Sprintf("metadata: Pairs got the odd number of input pairs for metadata: %d", len(kv)))
  76. }
  77. md := make(MD, len(kv)/2)
  78. for i := 0; i < len(kv); i += 2 {
  79. key := strings.ToLower(kv[i])
  80. md[key] = append(md[key], kv[i+1])
  81. }
  82. return md
  83. }
  84. // Len returns the number of items in md.
  85. func (md MD) Len() int {
  86. return len(md)
  87. }
  88. // Copy returns a copy of md.
  89. func (md MD) Copy() MD {
  90. out := make(MD, len(md))
  91. for k, v := range md {
  92. out[k] = copyOf(v)
  93. }
  94. return out
  95. }
  96. // Get obtains the values for a given key.
  97. //
  98. // k is converted to lowercase before searching in md.
  99. func (md MD) Get(k string) []string {
  100. k = strings.ToLower(k)
  101. return md[k]
  102. }
  103. // Set sets the value of a given key with a slice of values.
  104. //
  105. // k is converted to lowercase before storing in md.
  106. func (md MD) Set(k string, vals ...string) {
  107. if len(vals) == 0 {
  108. return
  109. }
  110. k = strings.ToLower(k)
  111. md[k] = vals
  112. }
  113. // Append adds the values to key k, not overwriting what was already stored at
  114. // that key.
  115. //
  116. // k is converted to lowercase before storing in md.
  117. func (md MD) Append(k string, vals ...string) {
  118. if len(vals) == 0 {
  119. return
  120. }
  121. k = strings.ToLower(k)
  122. md[k] = append(md[k], vals...)
  123. }
  124. // Delete removes the values for a given key k which is converted to lowercase
  125. // before removing it from md.
  126. func (md MD) Delete(k string) {
  127. k = strings.ToLower(k)
  128. delete(md, k)
  129. }
  130. // Join joins any number of mds into a single MD.
  131. //
  132. // The order of values for each key is determined by the order in which the mds
  133. // containing those values are presented to Join.
  134. func Join(mds ...MD) MD {
  135. out := MD{}
  136. for _, md := range mds {
  137. for k, v := range md {
  138. out[k] = append(out[k], v...)
  139. }
  140. }
  141. return out
  142. }
  143. type mdIncomingKey struct{}
  144. type mdOutgoingKey struct{}
  145. // NewIncomingContext creates a new context with incoming md attached. md must
  146. // not be modified after calling this function.
  147. func NewIncomingContext(ctx context.Context, md MD) context.Context {
  148. return context.WithValue(ctx, mdIncomingKey{}, md)
  149. }
  150. // NewOutgoingContext creates a new context with outgoing md attached. If used
  151. // in conjunction with AppendToOutgoingContext, NewOutgoingContext will
  152. // overwrite any previously-appended metadata. md must not be modified after
  153. // calling this function.
  154. func NewOutgoingContext(ctx context.Context, md MD) context.Context {
  155. return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md})
  156. }
  157. // AppendToOutgoingContext returns a new context with the provided kv merged
  158. // with any existing metadata in the context. Please refer to the documentation
  159. // of Pairs for a description of kv.
  160. func AppendToOutgoingContext(ctx context.Context, kv ...string) context.Context {
  161. if len(kv)%2 == 1 {
  162. panic(fmt.Sprintf("metadata: AppendToOutgoingContext got an odd number of input pairs for metadata: %d", len(kv)))
  163. }
  164. md, _ := ctx.Value(mdOutgoingKey{}).(rawMD)
  165. added := make([][]string, len(md.added)+1)
  166. copy(added, md.added)
  167. kvCopy := make([]string, 0, len(kv))
  168. for i := 0; i < len(kv); i += 2 {
  169. kvCopy = append(kvCopy, strings.ToLower(kv[i]), kv[i+1])
  170. }
  171. added[len(added)-1] = kvCopy
  172. return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md.md, added: added})
  173. }
  174. // FromIncomingContext returns the incoming metadata in ctx if it exists.
  175. //
  176. // All keys in the returned MD are lowercase.
  177. func FromIncomingContext(ctx context.Context) (MD, bool) {
  178. md, ok := ctx.Value(mdIncomingKey{}).(MD)
  179. if !ok {
  180. return nil, false
  181. }
  182. out := make(MD, len(md))
  183. for k, v := range md {
  184. // We need to manually convert all keys to lower case, because MD is a
  185. // map, and there's no guarantee that the MD attached to the context is
  186. // created using our helper functions.
  187. key := strings.ToLower(k)
  188. out[key] = copyOf(v)
  189. }
  190. return out, true
  191. }
  192. // ValueFromIncomingContext returns the metadata value corresponding to the metadata
  193. // key from the incoming metadata if it exists. Keys are matched in a case insensitive
  194. // manner.
  195. //
  196. // # Experimental
  197. //
  198. // Notice: This API is EXPERIMENTAL and may be changed or removed in a
  199. // later release.
  200. func ValueFromIncomingContext(ctx context.Context, key string) []string {
  201. md, ok := ctx.Value(mdIncomingKey{}).(MD)
  202. if !ok {
  203. return nil
  204. }
  205. if v, ok := md[key]; ok {
  206. return copyOf(v)
  207. }
  208. for k, v := range md {
  209. // Case insenitive comparison: MD is a map, and there's no guarantee
  210. // that the MD attached to the context is created using our helper
  211. // functions.
  212. if strings.EqualFold(k, key) {
  213. return copyOf(v)
  214. }
  215. }
  216. return nil
  217. }
  218. func copyOf(v []string) []string {
  219. vals := make([]string, len(v))
  220. copy(vals, v)
  221. return vals
  222. }
  223. // fromOutgoingContextRaw returns the un-merged, intermediary contents of rawMD.
  224. //
  225. // Remember to perform strings.ToLower on the keys, for both the returned MD (MD
  226. // is a map, there's no guarantee it's created using our helper functions) and
  227. // the extra kv pairs (AppendToOutgoingContext doesn't turn them into
  228. // lowercase).
  229. func fromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) {
  230. raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD)
  231. if !ok {
  232. return nil, nil, false
  233. }
  234. return raw.md, raw.added, true
  235. }
  236. // FromOutgoingContext returns the outgoing metadata in ctx if it exists.
  237. //
  238. // All keys in the returned MD are lowercase.
  239. func FromOutgoingContext(ctx context.Context) (MD, bool) {
  240. raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD)
  241. if !ok {
  242. return nil, false
  243. }
  244. mdSize := len(raw.md)
  245. for i := range raw.added {
  246. mdSize += len(raw.added[i]) / 2
  247. }
  248. out := make(MD, mdSize)
  249. for k, v := range raw.md {
  250. // We need to manually convert all keys to lower case, because MD is a
  251. // map, and there's no guarantee that the MD attached to the context is
  252. // created using our helper functions.
  253. key := strings.ToLower(k)
  254. out[key] = copyOf(v)
  255. }
  256. for _, added := range raw.added {
  257. if len(added)%2 == 1 {
  258. panic(fmt.Sprintf("metadata: FromOutgoingContext got an odd number of input pairs for metadata: %d", len(added)))
  259. }
  260. for i := 0; i < len(added); i += 2 {
  261. key := strings.ToLower(added[i])
  262. out[key] = append(out[key], added[i+1])
  263. }
  264. }
  265. return out, ok
  266. }
  267. type rawMD struct {
  268. md MD
  269. added [][]string
  270. }