github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/net/http/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  	"time"
    13  )
    14  
    15  // A Header represents the key-value pairs in an HTTP header.
    16  type Header map[string][]string
    17  
    18  // Add adds the key, value pair to the header.
    19  // It appends to any existing values associated with key.
    20  func (h Header) Add(key, value string) {
    21  	textproto.MIMEHeader(h).Add(key, value)
    22  }
    23  
    24  // Set sets the header entries associated with key to
    25  // the single element value.  It replaces any existing
    26  // values associated with key.
    27  func (h Header) Set(key, value string) {
    28  	textproto.MIMEHeader(h).Set(key, value)
    29  }
    30  
    31  // Get gets the first value associated with the given key.
    32  // If there are no values associated with the key, Get returns "".
    33  // To access multiple values of a key, access the map directly
    34  // with CanonicalHeaderKey.
    35  func (h Header) Get(key string) string {
    36  	return textproto.MIMEHeader(h).Get(key)
    37  }
    38  
    39  // get is like Get, but key must already be in CanonicalHeaderKey form.
    40  func (h Header) get(key string) string {
    41  	if v := h[key]; len(v) > 0 {
    42  		return v[0]
    43  	}
    44  	return ""
    45  }
    46  
    47  // Del deletes the values associated with key.
    48  func (h Header) Del(key string) {
    49  	textproto.MIMEHeader(h).Del(key)
    50  }
    51  
    52  // Write writes a header in wire format.
    53  func (h Header) Write(w io.Writer) error {
    54  	return h.WriteSubset(w, nil)
    55  }
    56  
    57  func (h Header) clone() Header {
    58  	h2 := make(Header, len(h))
    59  	for k, vv := range h {
    60  		vv2 := make([]string, len(vv))
    61  		copy(vv2, vv)
    62  		h2[k] = vv2
    63  	}
    64  	return h2
    65  }
    66  
    67  var timeFormats = []string{
    68  	TimeFormat,
    69  	time.RFC850,
    70  	time.ANSIC,
    71  }
    72  
    73  // ParseTime parses a time header (such as the Date: header),
    74  // trying each of the three formats allowed by HTTP/1.1:
    75  // TimeFormat, time.RFC850, and time.ANSIC.
    76  func ParseTime(text string) (t time.Time, err error) {
    77  	for _, layout := range timeFormats {
    78  		t, err = time.Parse(layout, text)
    79  		if err == nil {
    80  			return
    81  		}
    82  	}
    83  	return
    84  }
    85  
    86  var headerNewlineToSpace = strings.NewReplacer("\n", " ", "\r", " ")
    87  
    88  type writeStringer interface {
    89  	WriteString(string) (int, error)
    90  }
    91  
    92  // stringWriter implements WriteString on a Writer.
    93  type stringWriter struct {
    94  	w io.Writer
    95  }
    96  
    97  func (w stringWriter) WriteString(s string) (n int, err error) {
    98  	return w.w.Write([]byte(s))
    99  }
   100  
   101  type keyValues struct {
   102  	key    string
   103  	values []string
   104  }
   105  
   106  // A headerSorter implements sort.Interface by sorting a []keyValues
   107  // by key. It's used as a pointer, so it can fit in a sort.Interface
   108  // interface value without allocation.
   109  type headerSorter struct {
   110  	kvs []keyValues
   111  }
   112  
   113  func (s *headerSorter) Len() int           { return len(s.kvs) }
   114  func (s *headerSorter) Swap(i, j int)      { s.kvs[i], s.kvs[j] = s.kvs[j], s.kvs[i] }
   115  func (s *headerSorter) Less(i, j int) bool { return s.kvs[i].key < s.kvs[j].key }
   116  
   117  // TODO: convert this to a sync.Cache (issue 4720)
   118  var headerSorterCache = make(chan *headerSorter, 8)
   119  
   120  // sortedKeyValues returns h's keys sorted in the returned kvs
   121  // slice. The headerSorter used to sort is also returned, for possible
   122  // return to headerSorterCache.
   123  func (h Header) sortedKeyValues(exclude map[string]bool) (kvs []keyValues, hs *headerSorter) {
   124  	select {
   125  	case hs = <-headerSorterCache:
   126  	default:
   127  		hs = new(headerSorter)
   128  	}
   129  	if cap(hs.kvs) < len(h) {
   130  		hs.kvs = make([]keyValues, 0, len(h))
   131  	}
   132  	kvs = hs.kvs[:0]
   133  	for k, vv := range h {
   134  		if !exclude[k] {
   135  			kvs = append(kvs, keyValues{k, vv})
   136  		}
   137  	}
   138  	hs.kvs = kvs
   139  	sort.Sort(hs)
   140  	return kvs, hs
   141  }
   142  
   143  // WriteSubset writes a header in wire format.
   144  // If exclude is not nil, keys where exclude[key] == true are not written.
   145  func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
   146  	ws, ok := w.(writeStringer)
   147  	if !ok {
   148  		ws = stringWriter{w}
   149  	}
   150  	kvs, sorter := h.sortedKeyValues(exclude)
   151  	for _, kv := range kvs {
   152  		for _, v := range kv.values {
   153  			v = headerNewlineToSpace.Replace(v)
   154  			v = textproto.TrimString(v)
   155  			for _, s := range []string{kv.key, ": ", v, "\r\n"} {
   156  				if _, err := ws.WriteString(s); err != nil {
   157  					return err
   158  				}
   159  			}
   160  		}
   161  	}
   162  	select {
   163  	case headerSorterCache <- sorter:
   164  	default:
   165  	}
   166  	return nil
   167  }
   168  
   169  // CanonicalHeaderKey returns the canonical format of the
   170  // header key s.  The canonicalization converts the first
   171  // letter and any letter following a hyphen to upper case;
   172  // the rest are converted to lowercase.  For example, the
   173  // canonical key for "accept-encoding" is "Accept-Encoding".
   174  func CanonicalHeaderKey(s string) string { return textproto.CanonicalMIMEHeaderKey(s) }
   175  
   176  // hasToken returns whether token appears with v, ASCII
   177  // case-insensitive, with space or comma boundaries.
   178  // token must be all lowercase.
   179  // v may contain mixed cased.
   180  func hasToken(v, token string) bool {
   181  	if len(token) > len(v) || token == "" {
   182  		return false
   183  	}
   184  	if v == token {
   185  		return true
   186  	}
   187  	for sp := 0; sp <= len(v)-len(token); sp++ {
   188  		// Check that first character is good.
   189  		// The token is ASCII, so checking only a single byte
   190  		// is sufficient.  We skip this potential starting
   191  		// position if both the first byte and its potential
   192  		// ASCII uppercase equivalent (b|0x20) don't match.
   193  		// False positives ('^' => '~') are caught by EqualFold.
   194  		if b := v[sp]; b != token[0] && b|0x20 != token[0] {
   195  			continue
   196  		}
   197  		// Check that start pos is on a valid token boundary.
   198  		if sp > 0 && !isTokenBoundary(v[sp-1]) {
   199  			continue
   200  		}
   201  		// Check that end pos is on a valid token boundary.
   202  		if endPos := sp + len(token); endPos != len(v) && !isTokenBoundary(v[endPos]) {
   203  			continue
   204  		}
   205  		if strings.EqualFold(v[sp:sp+len(token)], token) {
   206  			return true
   207  		}
   208  	}
   209  	return false
   210  }
   211  
   212  func isTokenBoundary(b byte) bool {
   213  	return b == ' ' || b == ',' || b == '\t'
   214  }