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