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 // If there are no values associated with the key, Get returns "".
     36 // To access multiple values of a key, access the map directly
     37 // with CanonicalHeaderKey.
     38 func (h Header) Get(key string) string {
     39 	return textproto.MIMEHeader(h).Get(key)
     40 }
     41 
     42 // get is like Get, but key must already be in CanonicalHeaderKey form.
     43 func (h Header) get(key string) string {
     44 	if v := h[key]; len(v) > 0 {
     45 		return v[0]
     46 	}
     47 	return ""
     48 }
     49 
     50 // Del deletes the values associated with key.
     51 func (h Header) Del(key string) {
     52 	textproto.MIMEHeader(h).Del(key)
     53 }
     54 
     55 // Write writes a header in wire format.
     56 func (h Header) Write(w io.Writer) error {
     57 	return h.WriteSubset(w, nil)
     58 }
     59 
     60 func (h Header) clone() Header {
     61 	h2 := make(Header, len(h))
     62 	for k, vv := range h {
     63 		vv2 := make([]string, len(vv))
     64 		copy(vv2, vv)
     65 		h2[k] = vv2
     66 	}
     67 	return h2
     68 }
     69 
     70 var timeFormats = []string{
     71 	TimeFormat,
     72 	time.RFC850,
     73 	time.ANSIC,
     74 }
     75 
     76 // ParseTime parses a time header (such as the Date: header),
     77 // trying each of the three formats allowed by HTTP/1.1:
     78 // TimeFormat, time.RFC850, and time.ANSIC.
     79 func ParseTime(text string) (t time.Time, err error) {
     80 	for _, layout := range timeFormats {
     81 		t, err = time.Parse(layout, text)
     82 		if err == nil {
     83 			return
     84 		}
     85 	}
     86 	return
     87 }
     88 
     89 var headerNewlineToSpace = strings.NewReplacer("\n", " ", "\r", " ")
     90 
     91 type writeStringer interface {
     92 	WriteString(string) (int, error)
     93 }
     94 
     95 // stringWriter implements WriteString on a Writer.
     96 type stringWriter struct {
     97 	w io.Writer
     98 }
     99 
    100 func (w stringWriter) WriteString(s string) (n int, err error) {
    101 	return w.w.Write([]byte(s))
    102 }
    103 
    104 type keyValues struct {
    105 	key    string
    106 	values []string
    107 }
    108 
    109 // A headerSorter implements sort.Interface by sorting a []keyValues
    110 // by key. It's used as a pointer, so it can fit in a sort.Interface
    111 // interface value without allocation.
    112 type headerSorter struct {
    113 	kvs []keyValues
    114 }
    115 
    116 func (s *headerSorter) Len() int           { return len(s.kvs) }
    117 func (s *headerSorter) Swap(i, j int)      { s.kvs[i], s.kvs[j] = s.kvs[j], s.kvs[i] }
    118 func (s *headerSorter) Less(i, j int) bool { return s.kvs[i].key < s.kvs[j].key }
    119 
    120 var headerSorterPool = sync.Pool{
    121 	New: func() interface{} { return new(headerSorter) },
    122 }
    123 
    124 // sortedKeyValues returns h's keys sorted in the returned kvs
    125 // slice. The headerSorter used to sort is also returned, for possible
    126 // return to headerSorterCache.
    127 func (h Header) sortedKeyValues(exclude map[string]bool) (kvs []keyValues, hs *headerSorter) {
    128 	hs = headerSorterPool.Get().(*headerSorter)
    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 	headerSorterPool.Put(sorter)
    163 	return nil
    164 }
    165 
    166 // CanonicalHeaderKey returns the canonical format of the
    167 // header key s.  The canonicalization converts the first
    168 // letter and any letter following a hyphen to upper case;
    169 // the rest are converted to lowercase.  For example, the
    170 // canonical key for "accept-encoding" is "Accept-Encoding".
    171 // If s contains a space or invalid header field bytes, it is
    172 // returned without modifications.
    173 func CanonicalHeaderKey(s string) string { return textproto.CanonicalMIMEHeaderKey(s) }
    174 
    175 // hasToken reports whether token appears with v, ASCII
    176 // case-insensitive, with space or comma boundaries.
    177 // token must be all lowercase.
    178 // v may contain mixed cased.
    179 func hasToken(v, token string) bool {
    180 	if len(token) > len(v) || token == "" {
    181 		return false
    182 	}
    183 	if v == token {
    184 		return true
    185 	}
    186 	for sp := 0; sp <= len(v)-len(token); sp++ {
    187 		// Check that first character is good.
    188 		// The token is ASCII, so checking only a single byte
    189 		// is sufficient.  We skip this potential starting
    190 		// position if both the first byte and its potential
    191 		// ASCII uppercase equivalent (b|0x20) don't match.
    192 		// False positives ('^' => '~') are caught by EqualFold.
    193 		if b := v[sp]; b != token[0] && b|0x20 != token[0] {
    194 			continue
    195 		}
    196 		// Check that start pos is on a valid token boundary.
    197 		if sp > 0 && !isTokenBoundary(v[sp-1]) {
    198 			continue
    199 		}
    200 		// Check that end pos is on a valid token boundary.
    201 		if endPos := sp + len(token); endPos != len(v) && !isTokenBoundary(v[endPos]) {
    202 			continue
    203 		}
    204 		if strings.EqualFold(v[sp:sp+len(token)], token) {
    205 			return true
    206 		}
    207 	}
    208 	return false
    209 }
    210 
    211 func isTokenBoundary(b byte) bool {
    212 	return b == ' ' || b == ',' || b == '\t'
    213 }
    214