github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/transports/header.go (about)

     1  /*
     2   * Copyright 2023 Wang Min Xiang
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   * 	http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   */
    17  
    18  package transports
    19  
    20  import (
    21  	"bytes"
    22  	"github.com/aacfactory/fns/commons/bytex"
    23  	"net/textproto"
    24  	"sort"
    25  	"strconv"
    26  	"sync"
    27  )
    28  
    29  var (
    30  	ContentTypeHeaderName                        = []byte("Content-Type")
    31  	ContentTypeJsonHeaderValue                   = []byte("application/json")
    32  	ContentTypeTextHeaderValue                   = []byte("text/plain")
    33  	ContentTypeAvroHeaderValue                   = []byte("application/avro")
    34  	ContentLengthHeaderName                      = []byte("Content-Length")
    35  	AuthorizationHeaderName                      = []byte("Authorization")
    36  	CookieHeaderName                             = []byte("Cookie")
    37  	ConnectionHeaderName                         = []byte("Connection")
    38  	UpgradeHeaderName                            = []byte("Upgrade")
    39  	CloseHeaderValue                             = []byte("close")
    40  	AcceptEncodingHeaderName                     = []byte("Accept-Encoding")
    41  	ContentEncodingHeaderName                    = []byte("Content-Encoding")
    42  	ClearSiteDataHeaderName                      = []byte("Clear-Site-Data")
    43  	CacheControlHeaderName                       = []byte("Cache-Control")
    44  	AgeHeaderName                                = []byte("Age")
    45  	CacheControlHeaderNoStore                    = []byte("no-store")
    46  	CacheControlHeaderNoCache                    = []byte("no-cache")
    47  	ETagHeaderName                               = []byte("ETag")
    48  	CacheControlHeaderIfNonMatch                 = []byte("If-None-Match")
    49  	VaryHeaderName                               = []byte("Vary")
    50  	OriginHeaderName                             = []byte("Origin")
    51  	AcceptHeaderName                             = []byte("Accept")
    52  	AccessControlRequestMethodHeaderName         = []byte("Access-Control-Request-Method")
    53  	AccessControlRequestHeadersHeaderName        = []byte("Access-Control-Request-Headers")
    54  	AccessControlRequestPrivateNetworkHeaderName = []byte("Access-Control-Request-Private-Network")
    55  	AccessControlAllowOriginHeaderName           = []byte("Access-Control-Allow-Origin")
    56  	AccessControlAllowMethodsHeaderName          = []byte("Access-Control-Allow-Methods")
    57  	AccessControlAllowHeadersHeaderName          = []byte("Access-Control-Allow-Headers")
    58  	AccessControlAllowCredentialsHeaderName      = []byte("Access-Control-Allow-Credentials")
    59  	AccessControlAllowPrivateNetworkHeaderName   = []byte("Access-Control-Allow-Private-Network")
    60  	AccessControlMaxAgeHeaderName                = []byte("Access-Control-Max-Age")
    61  	AccessControlExposeHeadersHeaderName         = []byte("Access-Control-Expose-Headers")
    62  	XRequestedWithHeaderName                     = []byte("X-Requested-With")
    63  	TrueClientIpHeaderName                       = []byte("True-Client-Ip")
    64  	XRealIpHeaderName                            = []byte("X-Real-IP")
    65  	XForwardedForHeaderName                      = []byte("X-Forwarded-For")
    66  	RequestIdHeaderName                          = []byte("X-Fns-Request-Id")
    67  	SignatureHeaderName                          = []byte("X-Fns-Signature")
    68  	EndpointIdHeaderName                         = []byte("X-Fns-Endpoint-Id")
    69  	EndpointVersionHeaderName                    = []byte("X-Fns-Endpoint-Version")
    70  	RequestTimeoutHeaderName                     = []byte("X-Fns-Request-Timeout")
    71  	RequestVersionsHeaderName                    = []byte("X-Fns-Request-Version")
    72  	HandleLatencyHeaderName                      = []byte("X-Fns-Handle-Latency")
    73  	DeviceIdHeaderName                           = []byte("X-Fns-Device-Id")
    74  	DeviceIpHeaderName                           = []byte("X-Fns-Device-Ip")
    75  	DeprecatedHeaderName                         = []byte("X-Fns-Deprecated")
    76  	ResponseRetryAfterHeaderName                 = []byte("Retry-After")
    77  	UserHeaderNamePrefix                         = []byte("XU-")
    78  )
    79  
    80  type Header interface {
    81  	Add(key []byte, value []byte)
    82  	Set(key []byte, value []byte)
    83  	Get(key []byte) []byte
    84  	Del(key []byte)
    85  	Values(key []byte) [][]byte
    86  	Foreach(fn func(key []byte, values [][]byte))
    87  	Len() int
    88  	Reset()
    89  }
    90  
    91  var (
    92  	headerPool = sync.Pool{}
    93  )
    94  
    95  func AcquireHeader() Header {
    96  	cached := headerPool.Get()
    97  	if cached == nil {
    98  		return NewHeader()
    99  	}
   100  	return cached.(Header)
   101  }
   102  
   103  func ReleaseHeader(h Header) {
   104  	h.Reset()
   105  	headerPool.Put(h)
   106  }
   107  
   108  func NewHeader() Header {
   109  	hh := make(defaultHeader, 0, 1)
   110  	return &hh
   111  }
   112  
   113  type headerEntry struct {
   114  	name  []byte
   115  	value [][]byte
   116  }
   117  
   118  type defaultHeader []headerEntry
   119  
   120  func (h *defaultHeader) Add(key []byte, value []byte) {
   121  	hh := *h
   122  	key = bytex.FromString(textproto.CanonicalMIMEHeaderKey(bytex.ToString(key)))
   123  	for _, entry := range hh {
   124  		if bytes.Equal(entry.name, key) {
   125  			entry.value = append(entry.value, value)
   126  			return
   127  		}
   128  	}
   129  	hh = append(hh, headerEntry{
   130  		name:  key,
   131  		value: [][]byte{value},
   132  	})
   133  	*h = hh
   134  }
   135  
   136  func (h *defaultHeader) Set(key []byte, value []byte) {
   137  	hh := *h
   138  	key = bytex.FromString(textproto.CanonicalMIMEHeaderKey(bytex.ToString(key)))
   139  	for _, entry := range hh {
   140  		if bytes.Equal(entry.name, key) {
   141  			entry.value = [][]byte{value}
   142  			return
   143  		}
   144  	}
   145  	hh = append(hh, headerEntry{
   146  		name:  key,
   147  		value: [][]byte{value},
   148  	})
   149  	*h = hh
   150  }
   151  
   152  func (h *defaultHeader) Get(key []byte) []byte {
   153  	hh := *h
   154  	key = bytex.FromString(textproto.CanonicalMIMEHeaderKey(bytex.ToString(key)))
   155  	for _, entry := range hh {
   156  		if bytes.Equal(entry.name, key) {
   157  			return entry.value[0]
   158  		}
   159  	}
   160  	return nil
   161  }
   162  
   163  func (h *defaultHeader) Del(key []byte) {
   164  	hh := *h
   165  	key = bytex.FromString(textproto.CanonicalMIMEHeaderKey(bytex.ToString(key)))
   166  	n := -1
   167  	for i, entry := range hh {
   168  		if bytes.Equal(entry.name, key) {
   169  			n = i
   170  			break
   171  		}
   172  	}
   173  	if n == -1 {
   174  		return
   175  	}
   176  	hh = append(hh[:n], hh[n+1:]...)
   177  	*h = hh
   178  }
   179  
   180  func (h *defaultHeader) Values(key []byte) [][]byte {
   181  	hh := *h
   182  	key = bytex.FromString(textproto.CanonicalMIMEHeaderKey(bytex.ToString(key)))
   183  	for _, entry := range hh {
   184  		if bytes.Equal(entry.name, key) {
   185  			return entry.value
   186  		}
   187  	}
   188  	return nil
   189  }
   190  
   191  func (h *defaultHeader) Len() int {
   192  	return len(*h)
   193  }
   194  
   195  func (h *defaultHeader) Foreach(fn func(key []byte, values [][]byte)) {
   196  	hh := *h
   197  	for _, entry := range hh {
   198  		fn(entry.name, entry.value)
   199  	}
   200  }
   201  
   202  func (h *defaultHeader) Reset() {
   203  	hh := *h
   204  	hh = hh[:0]
   205  	*h = hh
   206  }
   207  
   208  type AcceptEncoding struct {
   209  	Name    []byte
   210  	Quality float64
   211  }
   212  
   213  type AcceptEncodings []AcceptEncoding
   214  
   215  func (encodings AcceptEncodings) Len() int {
   216  	return len(encodings)
   217  }
   218  
   219  func (encodings AcceptEncodings) Less(i, j int) bool {
   220  	return encodings[i].Quality < encodings[j].Quality
   221  }
   222  
   223  func (encodings AcceptEncodings) Swap(i, j int) {
   224  	encodings[i], encodings[j] = encodings[j], encodings[i]
   225  }
   226  
   227  func (encodings AcceptEncodings) Get(name []byte) (quality float64, has bool) {
   228  	for _, enc := range encodings {
   229  		if bytes.Equal(enc.Name, name) {
   230  			quality = enc.Quality
   231  			has = true
   232  			return
   233  		}
   234  	}
   235  	return
   236  }
   237  
   238  func (encodings AcceptEncodings) Add(name []byte, quality float64) AcceptEncodings {
   239  	return append(encodings, AcceptEncoding{
   240  		Name:    name,
   241  		Quality: quality,
   242  	})
   243  }
   244  
   245  func (encodings AcceptEncodings) WriteTo(header Header) {
   246  	p := make([]byte, 0, 1)
   247  	for i, encoding := range encodings {
   248  		if i > 0 {
   249  			p = append(p, ',', ' ')
   250  		}
   251  		p = append(encoding.Name)
   252  		if encoding.Quality > 0 {
   253  			p = append(p, ';')
   254  		}
   255  		p = append(p, bytex.FromString(strconv.FormatFloat(encoding.Quality, 'f', 1, 64))...)
   256  	}
   257  	header.Set(AcceptEncodingHeaderName, p)
   258  }
   259  
   260  var (
   261  	comma     = []byte{','}
   262  	semicolon = []byte{';'}
   263  )
   264  
   265  func GetAcceptEncodings(header Header) (encodings AcceptEncodings) {
   266  	p := header.Get(AcceptEncodingHeaderName)
   267  	if len(p) == 0 {
   268  		return
   269  	}
   270  	items := bytes.Split(p, comma)
   271  	encodings = make(AcceptEncodings, 0, len(items))
   272  	for _, item := range items {
   273  		idx := bytes.Index(item, semicolon)
   274  		if idx < 0 {
   275  			item = bytes.TrimSpace(item)
   276  			if len(item) == 0 {
   277  				continue
   278  			}
   279  			encodings = append(encodings, AcceptEncoding{
   280  				Name:    item,
   281  				Quality: 0,
   282  			})
   283  			continue
   284  		}
   285  		if idx == len(item) {
   286  			item = bytes.TrimSpace(item[0 : idx-1])
   287  			if len(item) == 0 {
   288  				continue
   289  			}
   290  			encodings = append(encodings, AcceptEncoding{
   291  				Name:    item,
   292  				Quality: 0,
   293  			})
   294  			continue
   295  		}
   296  		name := bytes.TrimSpace(item[0:idx])
   297  		if len(name) == 0 {
   298  			continue
   299  		}
   300  		qp := bytes.TrimSpace(bytes.TrimSpace(item[idx+1:]))
   301  		quality, qualityErr := strconv.ParseFloat(bytex.ToString(qp), 64)
   302  		if qualityErr != nil {
   303  			continue
   304  		}
   305  		encodings = append(encodings, AcceptEncoding{
   306  			Name:    name,
   307  			Quality: quality,
   308  		})
   309  	}
   310  	if len(encodings) == 0 {
   311  		return
   312  	}
   313  	sort.Sort(encodings)
   314  	return
   315  }
   316  
   317  func AddXU(header Header, name []byte, value []byte) {
   318  	if idx := bytes.Index(name, UserHeaderNamePrefix); idx < 0 {
   319  		name = append(UserHeaderNamePrefix, name...)
   320  	}
   321  	header.Add(name, value)
   322  }
   323  
   324  func SetXU(header Header, name []byte, value []byte) {
   325  	if idx := bytes.Index(name, UserHeaderNamePrefix); idx < 0 {
   326  		name = append(UserHeaderNamePrefix, name...)
   327  	}
   328  	header.Set(name, value)
   329  }
   330  
   331  func GetXU(header Header, name []byte) (value []byte) {
   332  	if idx := bytes.Index(name, UserHeaderNamePrefix); idx < 0 {
   333  		name = append(UserHeaderNamePrefix, name...)
   334  	}
   335  	value = header.Get(name)
   336  	return
   337  }
   338  
   339  func ValuesXU(header Header, name []byte) (value [][]byte) {
   340  	if idx := bytes.Index(name, UserHeaderNamePrefix); idx < 0 {
   341  		name = append(UserHeaderNamePrefix, name...)
   342  	}
   343  	value = header.Values(name)
   344  	return
   345  }