123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- /*
- *
- * Copyright 2014, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
- // Package metadata define the structure of the metadata supported by gRPC library.
- package metadata
- import (
- "encoding/base64"
- "fmt"
- "strings"
- "golang.org/x/net/context"
- )
- const (
- binHdrSuffix = "-bin"
- )
- // encodeKeyValue encodes key and value qualified for transmission via gRPC.
- // Transmitting binary headers violates HTTP/2 spec.
- // TODO(zhaoq): Maybe check if k is ASCII also.
- func encodeKeyValue(k, v string) (string, string) {
- k = strings.ToLower(k)
- if strings.HasSuffix(k, binHdrSuffix) {
- val := base64.StdEncoding.EncodeToString([]byte(v))
- v = string(val)
- }
- return k, v
- }
- // DecodeKeyValue returns the original key and value corresponding to the
- // encoded data in k, v.
- // If k is a binary header and v contains comma, v is split on comma before decoded,
- // and the decoded v will be joined with comma before returned.
- func DecodeKeyValue(k, v string) (string, string, error) {
- if !strings.HasSuffix(k, binHdrSuffix) {
- return k, v, nil
- }
- vvs := strings.Split(v, ",")
- for i, vv := range vvs {
- val, err := base64.StdEncoding.DecodeString(vv)
- if err != nil {
- return "", "", err
- }
- vvs[i] = string(val)
- }
- return k, strings.Join(vvs, ","), nil
- }
- // MD is a mapping from metadata keys to values. Users should use the following
- // two convenience functions New and Pairs to generate MD.
- type MD map[string][]string
- // New creates a MD from given key-value map.
- func New(m map[string]string) MD {
- md := MD{}
- for k, v := range m {
- key, val := encodeKeyValue(k, v)
- md[key] = append(md[key], val)
- }
- return md
- }
- // Pairs returns an MD formed by the mapping of key, value ...
- // Pairs panics if len(kv) is odd.
- func Pairs(kv ...string) MD {
- if len(kv)%2 == 1 {
- panic(fmt.Sprintf("metadata: Pairs got the odd number of input pairs for metadata: %d", len(kv)))
- }
- md := MD{}
- var k string
- for i, s := range kv {
- if i%2 == 0 {
- k = s
- continue
- }
- key, val := encodeKeyValue(k, s)
- md[key] = append(md[key], val)
- }
- return md
- }
- // Len returns the number of items in md.
- func (md MD) Len() int {
- return len(md)
- }
- // Copy returns a copy of md.
- func (md MD) Copy() MD {
- out := MD{}
- for k, v := range md {
- for _, i := range v {
- out[k] = append(out[k], i)
- }
- }
- return out
- }
- type mdKey struct{}
- // NewContext creates a new context with md attached.
- func NewContext(ctx context.Context, md MD) context.Context {
- return context.WithValue(ctx, mdKey{}, md)
- }
- // FromContext returns the MD in ctx if it exists.
- func FromContext(ctx context.Context) (md MD, ok bool) {
- md, ok = ctx.Value(mdKey{}).(MD)
- return
- }
|