libgo: update to Go 1.11
[official-gcc.git] / libgo / go / net / http / header.go
blob461ae9368ac15cc5681813ddb7ba8b92d2a46226
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.
5 package http
7 import (
8 "io"
9 "net/http/httptrace"
10 "net/textproto"
11 "sort"
12 "strings"
13 "sync"
14 "time"
17 var raceEnabled = false // set by race.go
19 // A Header represents the key-value pairs in an HTTP header.
20 type Header map[string][]string
22 // Add adds the key, value pair to the header.
23 // It appends to any existing values associated with key.
24 func (h Header) Add(key, value string) {
25 textproto.MIMEHeader(h).Add(key, value)
28 // Set sets the header entries associated with key to
29 // the single element value. It replaces any existing
30 // values associated with key.
31 func (h Header) Set(key, value string) {
32 textproto.MIMEHeader(h).Set(key, value)
35 // Get gets the first value associated with the given key.
36 // It is case insensitive; textproto.CanonicalMIMEHeaderKey is used
37 // to canonicalize the provided key.
38 // If there are no values associated with the key, Get returns "".
39 // To access multiple values of a key, or to use non-canonical keys,
40 // access the map directly.
41 func (h Header) Get(key string) string {
42 return textproto.MIMEHeader(h).Get(key)
45 // get is like Get, but key must already be in CanonicalHeaderKey form.
46 func (h Header) get(key string) string {
47 if v := h[key]; len(v) > 0 {
48 return v[0]
50 return ""
53 // Del deletes the values associated with key.
54 func (h Header) Del(key string) {
55 textproto.MIMEHeader(h).Del(key)
58 // Write writes a header in wire format.
59 func (h Header) Write(w io.Writer) error {
60 return h.write(w, nil)
63 func (h Header) write(w io.Writer, trace *httptrace.ClientTrace) error {
64 return h.writeSubset(w, nil, trace)
67 func (h Header) clone() Header {
68 h2 := make(Header, len(h))
69 for k, vv := range h {
70 vv2 := make([]string, len(vv))
71 copy(vv2, vv)
72 h2[k] = vv2
74 return h2
77 var timeFormats = []string{
78 TimeFormat,
79 time.RFC850,
80 time.ANSIC,
83 // ParseTime parses a time header (such as the Date: header),
84 // trying each of the three formats allowed by HTTP/1.1:
85 // TimeFormat, time.RFC850, and time.ANSIC.
86 func ParseTime(text string) (t time.Time, err error) {
87 for _, layout := range timeFormats {
88 t, err = time.Parse(layout, text)
89 if err == nil {
90 return
93 return
96 var headerNewlineToSpace = strings.NewReplacer("\n", " ", "\r", " ")
98 type writeStringer interface {
99 WriteString(string) (int, error)
102 // stringWriter implements WriteString on a Writer.
103 type stringWriter struct {
104 w io.Writer
107 func (w stringWriter) WriteString(s string) (n int, err error) {
108 return w.w.Write([]byte(s))
111 type keyValues struct {
112 key string
113 values []string
116 // A headerSorter implements sort.Interface by sorting a []keyValues
117 // by key. It's used as a pointer, so it can fit in a sort.Interface
118 // interface value without allocation.
119 type headerSorter struct {
120 kvs []keyValues
123 func (s *headerSorter) Len() int { return len(s.kvs) }
124 func (s *headerSorter) Swap(i, j int) { s.kvs[i], s.kvs[j] = s.kvs[j], s.kvs[i] }
125 func (s *headerSorter) Less(i, j int) bool { return s.kvs[i].key < s.kvs[j].key }
127 var headerSorterPool = sync.Pool{
128 New: func() interface{} { return new(headerSorter) },
131 // sortedKeyValues returns h's keys sorted in the returned kvs
132 // slice. The headerSorter used to sort is also returned, for possible
133 // return to headerSorterCache.
134 func (h Header) sortedKeyValues(exclude map[string]bool) (kvs []keyValues, hs *headerSorter) {
135 hs = headerSorterPool.Get().(*headerSorter)
136 if cap(hs.kvs) < len(h) {
137 hs.kvs = make([]keyValues, 0, len(h))
139 kvs = hs.kvs[:0]
140 for k, vv := range h {
141 if !exclude[k] {
142 kvs = append(kvs, keyValues{k, vv})
145 hs.kvs = kvs
146 sort.Sort(hs)
147 return kvs, hs
150 // WriteSubset writes a header in wire format.
151 // If exclude is not nil, keys where exclude[key] == true are not written.
152 func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
153 return h.writeSubset(w, exclude, nil)
156 func (h Header) writeSubset(w io.Writer, exclude map[string]bool, trace *httptrace.ClientTrace) error {
157 ws, ok := w.(writeStringer)
158 if !ok {
159 ws = stringWriter{w}
161 kvs, sorter := h.sortedKeyValues(exclude)
162 var formattedVals []string
163 for _, kv := range kvs {
164 for _, v := range kv.values {
165 v = headerNewlineToSpace.Replace(v)
166 v = textproto.TrimString(v)
167 for _, s := range []string{kv.key, ": ", v, "\r\n"} {
168 if _, err := ws.WriteString(s); err != nil {
169 headerSorterPool.Put(sorter)
170 return err
173 if trace != nil && trace.WroteHeaderField != nil {
174 formattedVals = append(formattedVals, v)
177 if trace != nil && trace.WroteHeaderField != nil {
178 trace.WroteHeaderField(kv.key, formattedVals)
179 formattedVals = nil
182 headerSorterPool.Put(sorter)
183 return nil
186 // CanonicalHeaderKey returns the canonical format of the
187 // header key s. The canonicalization converts the first
188 // letter and any letter following a hyphen to upper case;
189 // the rest are converted to lowercase. For example, the
190 // canonical key for "accept-encoding" is "Accept-Encoding".
191 // If s contains a space or invalid header field bytes, it is
192 // returned without modifications.
193 func CanonicalHeaderKey(s string) string { return textproto.CanonicalMIMEHeaderKey(s) }
195 // hasToken reports whether token appears with v, ASCII
196 // case-insensitive, with space or comma boundaries.
197 // token must be all lowercase.
198 // v may contain mixed cased.
199 func hasToken(v, token string) bool {
200 if len(token) > len(v) || token == "" {
201 return false
203 if v == token {
204 return true
206 for sp := 0; sp <= len(v)-len(token); sp++ {
207 // Check that first character is good.
208 // The token is ASCII, so checking only a single byte
209 // is sufficient. We skip this potential starting
210 // position if both the first byte and its potential
211 // ASCII uppercase equivalent (b|0x20) don't match.
212 // False positives ('^' => '~') are caught by EqualFold.
213 if b := v[sp]; b != token[0] && b|0x20 != token[0] {
214 continue
216 // Check that start pos is on a valid token boundary.
217 if sp > 0 && !isTokenBoundary(v[sp-1]) {
218 continue
220 // Check that end pos is on a valid token boundary.
221 if endPos := sp + len(token); endPos != len(v) && !isTokenBoundary(v[endPos]) {
222 continue
224 if strings.EqualFold(v[sp:sp+len(token)], token) {
225 return true
228 return false
231 func isTokenBoundary(b byte) bool {
232 return b == ' ' || b == ',' || b == '\t'
235 func cloneHeader(h Header) Header {
236 h2 := make(Header, len(h))
237 for k, vv := range h {
238 vv2 := make([]string, len(vv))
239 copy(vv2, vv)
240 h2[k] = vv2
242 return h2