go.uber.org/yarpc@v1.72.1/transport/http/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 http
    22  
    23  import (
    24  	"net/http"
    25  	"strings"
    26  
    27  	"go.uber.org/yarpc/api/transport"
    28  )
    29  
    30  // headerConverter converts HTTP headers to and from transport headers.
    31  type headerMapper struct{ Prefix string }
    32  
    33  var (
    34  	applicationHeaders = headerMapper{ApplicationHeaderPrefix}
    35  )
    36  
    37  // toHTTPHeaders converts application headers into transport headers.
    38  //
    39  // Headers are read from 'from' and written to 'to'. The final header collection
    40  // is returned.
    41  //
    42  // If 'to' is nil, a new map will be assigned.
    43  func (hm headerMapper) ToHTTPHeaders(from transport.Headers, to http.Header) http.Header {
    44  	if to == nil {
    45  		to = make(http.Header, from.Len())
    46  	}
    47  	for k, v := range from.Items() {
    48  		to.Add(hm.Prefix+k, v)
    49  	}
    50  	return to
    51  }
    52  
    53  // fromHTTPHeaders converts HTTP headers to application headers.
    54  //
    55  // Headers are read from 'from' and written to 'to'. The final header collection
    56  // is returned.
    57  //
    58  // If 'to' is nil, a new map will be assigned.
    59  func (hm headerMapper) FromHTTPHeaders(from http.Header, to transport.Headers) transport.Headers {
    60  	prefixLen := len(hm.Prefix)
    61  	for k := range from {
    62  		if strings.HasPrefix(k, hm.Prefix) {
    63  			key := k[prefixLen:]
    64  			to = to.With(key, from.Get(k))
    65  		}
    66  		// Note: undefined behavior for multiple occurrences of the same header
    67  	}
    68  	return to
    69  }
    70  
    71  func (hm headerMapper) deleteHTTP2PseudoHeadersIfNeeded(from transport.Headers) transport.Headers {
    72  	// deleting all http2 pseudo-header fields
    73  	// RFC https://tools.ietf.org/html/rfc7540#section-8.1.2.3
    74  	// :method -> this can be removed, YARPC uses POST for all HTTP requests.
    75  	// :path -> this can be removed, this is handled by YARPC with RPC-procedure.
    76  	// :scheme -> this can be removed, scheme is defined in the URI (http or https).
    77  	// :authority -> even if the RFC advises to copy :authority into host header, it is safe to remove it
    78  	// here. Host of the request is controlled through the YARPC outbound configuration.
    79  	for _, k := range _http2PseudoHeaders {
    80  		if _, ok := from.Get(k); ok {
    81  			from.Del(k)
    82  		}
    83  	}
    84  	return from
    85  }