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 }