github.com/stackdocker/rkt@v0.10.1-0.20151109095037-1aa827478248/Godeps/_workspace/src/google.golang.org/grpc/metadata/metadata.go (about)

     1  /*
     2   *
     3   * Copyright 2014, Google Inc.
     4   * All rights reserved.
     5   *
     6   * Redistribution and use in source and binary forms, with or without
     7   * modification, are permitted provided that the following conditions are
     8   * met:
     9   *
    10   *     * Redistributions of source code must retain the above copyright
    11   * notice, this list of conditions and the following disclaimer.
    12   *     * Redistributions in binary form must reproduce the above
    13   * copyright notice, this list of conditions and the following disclaimer
    14   * in the documentation and/or other materials provided with the
    15   * distribution.
    16   *     * Neither the name of Google Inc. nor the names of its
    17   * contributors may be used to endorse or promote products derived from
    18   * this software without specific prior written permission.
    19   *
    20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    21   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    22   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    23   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    24   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    25   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    26   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    28   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    29   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    30   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31   *
    32   */
    33  
    34  // Package metadata define the structure of the metadata supported by gRPC library.
    35  package metadata
    36  
    37  import (
    38  	"encoding/base64"
    39  	"fmt"
    40  	"strings"
    41  
    42  	"github.com/coreos/rkt/Godeps/_workspace/src/golang.org/x/net/context"
    43  )
    44  
    45  const (
    46  	binHdrSuffix = "-bin"
    47  )
    48  
    49  // grpc-http2 requires ASCII header key and value (more detail can be found in
    50  // "Requests" subsection in go/grpc-http2).
    51  func isASCII(s string) bool {
    52  	for _, c := range s {
    53  		if c > 127 {
    54  			return false
    55  		}
    56  	}
    57  	return true
    58  }
    59  
    60  // encodeKeyValue encodes key and value qualified for transmission via gRPC.
    61  // Transmitting binary headers violates HTTP/2 spec.
    62  // TODO(zhaoq): Maybe check if k is ASCII also.
    63  func encodeKeyValue(k, v string) (string, string) {
    64  	if isASCII(v) {
    65  		return k, v
    66  	}
    67  	key := strings.ToLower(k + binHdrSuffix)
    68  	val := base64.StdEncoding.EncodeToString([]byte(v))
    69  	return key, string(val)
    70  }
    71  
    72  // DecodeKeyValue returns the original key and value corresponding to the
    73  // encoded data in k, v.
    74  func DecodeKeyValue(k, v string) (string, string, error) {
    75  	if !strings.HasSuffix(k, binHdrSuffix) {
    76  		return k, v, nil
    77  	}
    78  	key := k[:len(k)-len(binHdrSuffix)]
    79  	val, err := base64.StdEncoding.DecodeString(v)
    80  	if err != nil {
    81  		return "", "", err
    82  	}
    83  	return key, string(val), nil
    84  }
    85  
    86  // MD is a mapping from metadata keys to values. Users should use the following
    87  // two convenience functions New and Pairs to generate MD.
    88  type MD map[string][]string
    89  
    90  // New creates a MD from given key-value map.
    91  func New(m map[string]string) MD {
    92  	md := MD{}
    93  	for k, v := range m {
    94  		key, val := encodeKeyValue(k, v)
    95  		md[key] = append(md[key], val)
    96  	}
    97  	return md
    98  }
    99  
   100  // Pairs returns an MD formed by the mapping of key, value ...
   101  // Pairs panics if len(kv) is odd.
   102  func Pairs(kv ...string) MD {
   103  	if len(kv)%2 == 1 {
   104  		panic(fmt.Sprintf("metadata: Pairs got the odd number of input pairs for metadata: %d", len(kv)))
   105  	}
   106  	md := MD{}
   107  	var k string
   108  	for i, s := range kv {
   109  		if i%2 == 0 {
   110  			k = s
   111  			continue
   112  		}
   113  		key, val := encodeKeyValue(k, s)
   114  		md[key] = append(md[key], val)
   115  	}
   116  	return md
   117  }
   118  
   119  // Len returns the number of items in md.
   120  func (md MD) Len() int {
   121  	return len(md)
   122  }
   123  
   124  // Copy returns a copy of md.
   125  func (md MD) Copy() MD {
   126  	out := MD{}
   127  	for k, v := range md {
   128  		for _, i := range v {
   129  			out[k] = append(out[k], i)
   130  		}
   131  	}
   132  	return out
   133  }
   134  
   135  type mdKey struct{}
   136  
   137  // NewContext creates a new context with md attached.
   138  func NewContext(ctx context.Context, md MD) context.Context {
   139  	return context.WithValue(ctx, mdKey{}, md)
   140  }
   141  
   142  // FromContext returns the MD in ctx if it exists.
   143  func FromContext(ctx context.Context) (md MD, ok bool) {
   144  	md, ok = ctx.Value(mdKey{}).(MD)
   145  	return
   146  }