go.uber.org/yarpc@v1.72.1/api/transport/header.go (about)

     1  // Copyright (c) 2022 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package transport
    22  
    23  import "strings"
    24  
    25  // CanonicalizeHeaderKey canonicalizes the given header key for storage into
    26  // Headers.
    27  func CanonicalizeHeaderKey(k string) string {
    28  	// TODO: Deal with unsupported header keys (anything that's not a valid HTTP
    29  	// header key).
    30  	return strings.ToLower(k)
    31  }
    32  
    33  // Headers is the transport-level representation of application headers.
    34  //
    35  // 	var headers transport.Headers
    36  // 	headers = headers.With("foo", "bar")
    37  // 	headers = headers.With("baz", "qux")
    38  type Headers struct {
    39  	// This representation allows us to make zero-value valid
    40  	items map[string]string
    41  	// original non-canonical headers, foo-bar will be treated as different value than Foo-bar
    42  	originalItems map[string]string
    43  }
    44  
    45  // NewHeaders builds a new Headers object.
    46  func NewHeaders() Headers {
    47  	return Headers{}
    48  }
    49  
    50  // NewHeadersWithCapacity allocates a new Headers object with the given
    51  // capacity. A capacity of zero or less is ignored.
    52  func NewHeadersWithCapacity(capacity int) Headers {
    53  	if capacity <= 0 {
    54  		return Headers{}
    55  	}
    56  	return Headers{
    57  		items:         make(map[string]string, capacity),
    58  		originalItems: make(map[string]string, capacity),
    59  	}
    60  }
    61  
    62  // With returns a Headers object with the given key-value pair added to it.
    63  //
    64  // The returned object MAY not point to the same Headers underlying data store
    65  // as the original Headers so the returned Headers MUST always be used instead
    66  // of the original object.
    67  //
    68  // 	headers = headers.With("foo", "bar").With("baz", "qux")
    69  func (h Headers) With(k, v string) Headers {
    70  	if h.items == nil {
    71  		h.items = make(map[string]string)
    72  		h.originalItems = make(map[string]string)
    73  	}
    74  	h.items[CanonicalizeHeaderKey(k)] = v
    75  	h.originalItems[k] = v
    76  	return h
    77  }
    78  
    79  // Del deletes the header with the given name from the Headers map.
    80  //
    81  // This is a no-op if the key does not exist.
    82  func (h Headers) Del(k string) {
    83  	delete(h.items, CanonicalizeHeaderKey(k))
    84  	delete(h.originalItems, k)
    85  }
    86  
    87  // Get retrieves the value associated with the given header name.
    88  func (h Headers) Get(k string) (string, bool) {
    89  	v, ok := h.items[CanonicalizeHeaderKey(k)]
    90  	return v, ok
    91  }
    92  
    93  // Len returns the number of headers defined on this object.
    94  func (h Headers) Len() int {
    95  	return len(h.items)
    96  }
    97  
    98  // Items returns the underlying map for this Headers object. The returned map
    99  // MUST NOT be changed. Doing so will result in undefined behavior.
   100  //
   101  // Keys in the map are normalized using CanonicalizeHeaderKey.
   102  func (h Headers) Items() map[string]string {
   103  	return h.items
   104  }
   105  
   106  // OriginalItems returns the non-canonicalized version of the underlying map
   107  // for this Headers object. The returned map MUST NOT be changed.
   108  // Doing so will result in undefined behavior.
   109  func (h Headers) OriginalItems() map[string]string {
   110  	return h.originalItems
   111  }
   112  
   113  // HeadersFromMap builds a new Headers object from the given map of header
   114  // key-value pairs.
   115  func HeadersFromMap(m map[string]string) Headers {
   116  	if len(m) == 0 {
   117  		return Headers{}
   118  	}
   119  	headers := NewHeadersWithCapacity(len(m))
   120  	for k, v := range m {
   121  		headers = headers.With(k, v)
   122  	}
   123  	return headers
   124  }