github.com/useflyent/fhttp@v0.0.0-20211004035111-333f430cfbbf/header.go (about)

     1  // Copyright 2010 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package http
     6  
     7  import (
     8  	"io"
     9  	"net/textproto"
    10  	"sort"
    11  	"strings"
    12  	"sync"
    13  	"time"
    14  
    15  	"github.com/useflyent/fhttp/httptrace"
    16  )
    17  
    18  // A Header represents the Key-value pairs in an HTTP header.
    19  //
    20  // The keys should be in canonical form, as returned by
    21  // CanonicalHeaderKey.
    22  type Header map[string][]string
    23  
    24  // HeaderOrderKey is a magic Key for ResponseWriter.Header map keys
    25  // that, if present, defines a header order that will be used to
    26  // write the headers onto wire. The order of the slice defined how the headers
    27  // will be sorted. A defined Key goes before an undefined Key.
    28  //
    29  // This is the only way to specify some order, because maps don't
    30  // have a a stable iteration order. If no order is given, headers will
    31  // be sorted lexicographically.
    32  //
    33  // According to RFC2616 it is good practice to send general-header fields
    34  // first, followed by request-header or response-header fields and ending
    35  // with entity-header fields.
    36  const HeaderOrderKey = "Header-Order:"
    37  
    38  // PHeaderOrderKey is a magic Key for setting http2 pseudo header order.
    39  // If the header is nil it will use regular GoLang header order.
    40  // Valid fields are :authority, :method, :path, :scheme
    41  const PHeaderOrderKey = "PHeader-Order:"
    42  
    43  // Add adds the Key, value pair to the header.
    44  // It appends to any existing Values associated with Key.
    45  // The Key is case insensitive; it is canonicalized by
    46  // CanonicalHeaderKey.
    47  func (h Header) Add(key, value string) {
    48  	textproto.MIMEHeader(h).Add(key, value)
    49  }
    50  
    51  // Set sets the header entries associated with Key to the
    52  // single element value. It replaces any existing Values
    53  // associated with Key. The Key is case insensitive; it is
    54  // canonicalized by textproto.CanonicalMIMEHeaderKey.
    55  // To use non-canonical keys, assign to the map directly.
    56  func (h Header) Set(key, value string) {
    57  	textproto.MIMEHeader(h).Set(key, value)
    58  }
    59  
    60  // Get gets the first value associated with the given Key. If
    61  // there are no Values associated with the Key, Get returns "".
    62  // It is case insensitive; textproto.CanonicalMIMEHeaderKey is
    63  // used to canonicalize the provided Key. To use non-canonical keys,
    64  // access the map directly.
    65  func (h Header) Get(key string) string {
    66  	return textproto.MIMEHeader(h).Get(key)
    67  }
    68  
    69  // Values returns all Values associated with the given Key.
    70  // It is case insensitive; textproto.CanonicalMIMEHeaderKey is
    71  // used to canonicalize the provided Key. To use non-canonical
    72  // keys, access the map directly.
    73  // The returned slice is not a copy.
    74  func (h Header) Values(key string) []string {
    75  	return textproto.MIMEHeader(h).Values(key)
    76  }
    77  
    78  // get is like Get, but Key must already be in CanonicalHeaderKey form.
    79  func (h Header) get(key string) string {
    80  	if v := h[key]; len(v) > 0 {
    81  		return v[0]
    82  	}
    83  	return ""
    84  }
    85  
    86  // has reports whether h has the provided Key defined, even if it's
    87  // set to 0-length slice.
    88  func (h Header) has(key string) bool {
    89  	_, ok := h[key]
    90  	return ok
    91  }
    92  
    93  // Del deletes the Values associated with Key.
    94  // The Key is case insensitive; it is canonicalized by
    95  // CanonicalHeaderKey.
    96  func (h Header) Del(key string) {
    97  	textproto.MIMEHeader(h).Del(key)
    98  }
    99  
   100  // Write writes a header in wire format.
   101  func (h Header) Write(w io.Writer) error {
   102  	return h.write(w, nil)
   103  }
   104  
   105  func (h Header) write(w io.Writer, trace *httptrace.ClientTrace) error {
   106  	return h.writeSubset(w, nil, trace)
   107  }
   108  
   109  // Clone returns a copy of h or nil if h is nil.
   110  func (h Header) Clone() Header {
   111  	if h == nil {
   112  		return nil
   113  	}
   114  
   115  	// Find total number of Values.
   116  	nv := 0
   117  	for _, vv := range h {
   118  		nv += len(vv)
   119  	}
   120  	sv := make([]string, nv) // shared backing array for headers' Values
   121  	h2 := make(Header, len(h))
   122  	for k, vv := range h {
   123  		n := copy(sv, vv)
   124  		h2[k] = sv[:n:n]
   125  		sv = sv[n:]
   126  	}
   127  	return h2
   128  }
   129  
   130  var timeFormats = []string{
   131  	TimeFormat,
   132  	time.RFC850,
   133  	time.ANSIC,
   134  }
   135  
   136  // ParseTime parses a time header (such as the Date: header),
   137  // trying each of the three formats allowed by HTTP/1.1:
   138  // TimeFormat, time.RFC850, and time.ANSIC.
   139  func ParseTime(text string) (t time.Time, err error) {
   140  	for _, layout := range timeFormats {
   141  		t, err = time.Parse(layout, text)
   142  		if err == nil {
   143  			return
   144  		}
   145  	}
   146  	return
   147  }
   148  
   149  var headerNewlineToSpace = strings.NewReplacer("\n", " ", "\r", " ")
   150  
   151  // stringWriter implements WriteString on a Writer.
   152  type stringWriter struct {
   153  	w io.Writer
   154  }
   155  
   156  func (w stringWriter) WriteString(s string) (n int, err error) {
   157  	return w.w.Write([]byte(s))
   158  }
   159  
   160  type HeaderKeyValues struct {
   161  	Key    string
   162  	Values []string
   163  }
   164  
   165  // A headerSorter implements sort.Interface by sorting a []keyValues
   166  // by the given order, if not nil, or by Key otherwise.
   167  // It's used as a pointer, so it can fit in a sort.Interface
   168  // interface value without allocation.
   169  type headerSorter struct {
   170  	kvs   []HeaderKeyValues
   171  	order map[string]int
   172  }
   173  
   174  func (s *headerSorter) Len() int      { return len(s.kvs) }
   175  func (s *headerSorter) Swap(i, j int) { s.kvs[i], s.kvs[j] = s.kvs[j], s.kvs[i] }
   176  func (s *headerSorter) Less(i, j int) bool {
   177  	// If the order isn't defined, sort lexicographically.
   178  	if s.order == nil {
   179  		return s.kvs[i].Key < s.kvs[j].Key
   180  	}
   181  	//idxi, iok := s.order[s.kvs[i].Key]
   182  	//idxj, jok := s.order[s.kvs[j].Key]
   183  	idxi, iok := s.order[strings.ToLower(s.kvs[i].Key)]
   184  	idxj, jok := s.order[strings.ToLower(s.kvs[j].Key)]
   185  	if !iok && !jok {
   186  		return s.kvs[i].Key < s.kvs[j].Key
   187  	} else if !iok && jok {
   188  		return false
   189  	} else if iok && !jok {
   190  		return true
   191  	}
   192  	return idxi < idxj
   193  }
   194  
   195  var headerSorterPool = sync.Pool{
   196  	New: func() interface{} { return new(headerSorter) },
   197  }
   198  
   199  var mutex = &sync.RWMutex{}
   200  
   201  // SortedKeyValues returns h's keys sorted in the returned kvs
   202  // slice. The headerSorter used to sort is also returned, for possible
   203  // return to headerSorterCache.
   204  func (h Header) SortedKeyValues(exclude map[string]bool) (kvs []HeaderKeyValues, hs *headerSorter) {
   205  	hs = headerSorterPool.Get().(*headerSorter)
   206  	if cap(hs.kvs) < len(h) {
   207  		hs.kvs = make([]HeaderKeyValues, 0, len(h))
   208  	}
   209  	kvs = hs.kvs[:0]
   210  	for k, vv := range h {
   211  		mutex.RLock()
   212  		if !exclude[k] {
   213  			kvs = append(kvs, HeaderKeyValues{k, vv})
   214  		}
   215  		mutex.RUnlock()
   216  	}
   217  	hs.kvs = kvs
   218  	sort.Sort(hs)
   219  	return kvs, hs
   220  }
   221  
   222  func (h Header) SortedKeyValuesBy(order map[string]int, exclude map[string]bool) (kvs []HeaderKeyValues, hs *headerSorter) {
   223  	hs = headerSorterPool.Get().(*headerSorter)
   224  	if cap(hs.kvs) < len(h) {
   225  		hs.kvs = make([]HeaderKeyValues, 0, len(h))
   226  	}
   227  	kvs = hs.kvs[:0]
   228  	for k, vv := range h {
   229  		mutex.RLock()
   230  		if !exclude[k] {
   231  			kvs = append(kvs, HeaderKeyValues{k, vv})
   232  		}
   233  		mutex.RUnlock()
   234  	}
   235  	hs.kvs = kvs
   236  	hs.order = order
   237  	sort.Sort(hs)
   238  
   239  	return kvs, hs
   240  }
   241  
   242  // WriteSubset writes a header in wire format.
   243  // If exclude is not nil, keys where exclude[Key] == true are not written.
   244  // Keys are not canonicalized before checking the exclude map.
   245  func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
   246  	return h.writeSubset(w, exclude, nil)
   247  }
   248  
   249  func (h Header) writeSubset(w io.Writer, exclude map[string]bool, trace *httptrace.ClientTrace) error {
   250  	ws, ok := w.(io.StringWriter)
   251  	if !ok {
   252  		ws = stringWriter{w}
   253  	}
   254  
   255  	var kvs []HeaderKeyValues
   256  	var sorter *headerSorter
   257  
   258  	// Check if the HeaderOrder is defined.
   259  	if headerOrder, ok := h[HeaderOrderKey]; ok {
   260  		order := make(map[string]int)
   261  		for i, v := range headerOrder {
   262  			order[v] = i
   263  		}
   264  		if exclude == nil {
   265  			exclude = make(map[string]bool)
   266  		}
   267  		mutex.Lock()
   268  		exclude[HeaderOrderKey] = true
   269  		exclude[PHeaderOrderKey] = true
   270  		mutex.Unlock()
   271  		kvs, sorter = h.SortedKeyValuesBy(order, exclude)
   272  	} else {
   273  		kvs, sorter = h.SortedKeyValues(exclude)
   274  	}
   275  
   276  	var formattedVals []string
   277  	for _, kv := range kvs {
   278  		for _, v := range kv.Values {
   279  			v = headerNewlineToSpace.Replace(v)
   280  			v = textproto.TrimString(v)
   281  			for _, s := range []string{kv.Key, ": ", v, "\r\n"} {
   282  				if _, err := ws.WriteString(s); err != nil {
   283  					headerSorterPool.Put(sorter)
   284  					return err
   285  				}
   286  			}
   287  			if trace != nil && trace.WroteHeaderField != nil {
   288  				formattedVals = append(formattedVals, v)
   289  			}
   290  		}
   291  		if trace != nil && trace.WroteHeaderField != nil {
   292  			trace.WroteHeaderField(kv.Key, formattedVals)
   293  			formattedVals = nil
   294  		}
   295  	}
   296  	headerSorterPool.Put(sorter)
   297  	return nil
   298  }
   299  
   300  // CanonicalHeaderKey returns the canonical format of the
   301  // header Key s. The canonicalization converts the first
   302  // letter and any letter following a hyphen to upper case;
   303  // the rest are converted to lowercase. For example, the
   304  // canonical Key for "accept-encoding" is "Accept-Encoding".
   305  // If s contains a space or invalid header field bytes, it is
   306  // returned without modifications.
   307  func CanonicalHeaderKey(s string) string { return textproto.CanonicalMIMEHeaderKey(s) }
   308  
   309  // hasToken reports whether token appears with v, ASCII
   310  // case-insensitive, with space or comma boundaries.
   311  // token must be all lowercase.
   312  // v may contain mixed cased.
   313  func hasToken(v, token string) bool {
   314  	if len(token) > len(v) || token == "" {
   315  		return false
   316  	}
   317  	if v == token {
   318  		return true
   319  	}
   320  	for sp := 0; sp <= len(v)-len(token); sp++ {
   321  		// Check that first character is good.
   322  		// The token is ASCII, so checking only a single byte
   323  		// is sufficient. We skip this potential starting
   324  		// position if both the first byte and its potential
   325  		// ASCII uppercase equivalent (b|0x20) don't match.
   326  		// False positives ('^' => '~') are caught by EqualFold.
   327  		if b := v[sp]; b != token[0] && b|0x20 != token[0] {
   328  			continue
   329  		}
   330  		// Check that start pos is on a valid token boundary.
   331  		if sp > 0 && !isTokenBoundary(v[sp-1]) {
   332  			continue
   333  		}
   334  		// Check that end pos is on a valid token boundary.
   335  		if endPos := sp + len(token); endPos != len(v) && !isTokenBoundary(v[endPos]) {
   336  			continue
   337  		}
   338  		if strings.EqualFold(v[sp:sp+len(token)], token) {
   339  			return true
   340  		}
   341  	}
   342  	return false
   343  }
   344  
   345  func isTokenBoundary(b byte) bool {
   346  	return b == ' ' || b == ',' || b == '\t'
   347  }