Copyright 2010 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package http

import (
	
	
	
	
	
	
	
)
A Header represents the key-value pairs in an HTTP header. The keys should be in canonical form, as returned by CanonicalHeaderKey.
type Header map[string][]string
Add adds the key, value pair to the header. It appends to any existing values associated with key. The key is case insensitive; it is canonicalized by CanonicalHeaderKey.
func ( Header) (,  string) {
	textproto.MIMEHeader().Add(, )
}
Set sets the header entries associated with key to the single element value. It replaces any existing values associated with key. The key is case insensitive; it is canonicalized by textproto.CanonicalMIMEHeaderKey. To use non-canonical keys, assign to the map directly.
func ( Header) (,  string) {
	textproto.MIMEHeader().Set(, )
}
Get gets the first value associated with the given key. If there are no values associated with the key, Get returns "". It is case insensitive; textproto.CanonicalMIMEHeaderKey is used to canonicalize the provided key. To use non-canonical keys, access the map directly.
func ( Header) ( string) string {
	return textproto.MIMEHeader().Get()
}
Values returns all values associated with the given key. It is case insensitive; textproto.CanonicalMIMEHeaderKey is used to canonicalize the provided key. To use non-canonical keys, access the map directly. The returned slice is not a copy.
func ( Header) ( string) []string {
	return textproto.MIMEHeader().Values()
}
get is like Get, but key must already be in CanonicalHeaderKey form.
func ( Header) ( string) string {
	if  := []; len() > 0 {
		return [0]
	}
	return ""
}
has reports whether h has the provided key defined, even if it's set to 0-length slice.
func ( Header) ( string) bool {
	,  := []
	return 
}
Del deletes the values associated with key. The key is case insensitive; it is canonicalized by CanonicalHeaderKey.
func ( Header) ( string) {
	textproto.MIMEHeader().Del()
}
Write writes a header in wire format.
func ( Header) ( io.Writer) error {
	return .write(, nil)
}

func ( Header) ( io.Writer,  *httptrace.ClientTrace) error {
	return .writeSubset(, nil, )
}
Clone returns a copy of h or nil if h is nil.
func ( Header) () Header {
	if  == nil {
		return nil
	}
Find total number of values.
	 := 0
	for ,  := range  {
		 += len()
	}
	 := make([]string, ) // shared backing array for headers' values
	 := make(Header, len())
	for ,  := range  {
		 := copy(, )
		[] = [::]
		 = [:]
	}
	return 
}

var timeFormats = []string{
	TimeFormat,
	time.RFC850,
	time.ANSIC,
}
ParseTime parses a time header (such as the Date: header), trying each of the three formats allowed by HTTP/1.1: TimeFormat, time.RFC850, and time.ANSIC.
func ( string) ( time.Time,  error) {
	for ,  := range timeFormats {
		,  = time.Parse(, )
		if  == nil {
			return
		}
	}
	return
}

var headerNewlineToSpace = strings.NewReplacer("\n", " ", "\r", " ")
stringWriter implements WriteString on a Writer.
type stringWriter struct {
	w io.Writer
}

func ( stringWriter) ( string) ( int,  error) {
	return .w.Write([]byte())
}

type keyValues struct {
	key    string
	values []string
}
A headerSorter implements sort.Interface by sorting a []keyValues by key. It's used as a pointer, so it can fit in a sort.Interface interface value without allocation.
type headerSorter struct {
	kvs []keyValues
}

func ( *headerSorter) () int           { return len(.kvs) }
func ( *headerSorter) (,  int)      { .kvs[], .kvs[] = .kvs[], .kvs[] }
func ( *headerSorter) (,  int) bool { return .kvs[].key < .kvs[].key }

var headerSorterPool = sync.Pool{
	New: func() interface{} { return new(headerSorter) },
}
sortedKeyValues returns h's keys sorted in the returned kvs slice. The headerSorter used to sort is also returned, for possible return to headerSorterCache.
func ( Header) ( map[string]bool) ( []keyValues,  *headerSorter) {
	 = headerSorterPool.Get().(*headerSorter)
	if cap(.kvs) < len() {
		.kvs = make([]keyValues, 0, len())
	}
	 = .kvs[:0]
	for ,  := range  {
		if ![] {
			 = append(, keyValues{, })
		}
	}
	.kvs = 
	sort.Sort()
	return , 
}
WriteSubset writes a header in wire format. If exclude is not nil, keys where exclude[key] == true are not written. Keys are not canonicalized before checking the exclude map.
func ( Header) ( io.Writer,  map[string]bool) error {
	return .writeSubset(, , nil)
}

func ( Header) ( io.Writer,  map[string]bool,  *httptrace.ClientTrace) error {
	,  := .(io.StringWriter)
	if ! {
		 = stringWriter{}
	}
	,  := .sortedKeyValues()
	var  []string
	for ,  := range  {
		for ,  := range .values {
			 = headerNewlineToSpace.Replace()
			 = textproto.TrimString()
			for ,  := range []string{.key, ": ", , "\r\n"} {
				if ,  := .WriteString();  != nil {
					headerSorterPool.Put()
					return 
				}
			}
			if  != nil && .WroteHeaderField != nil {
				 = append(, )
			}
		}
		if  != nil && .WroteHeaderField != nil {
			.WroteHeaderField(.key, )
			 = nil
		}
	}
	headerSorterPool.Put()
	return nil
}
CanonicalHeaderKey returns the canonical format of the header key s. The canonicalization converts the first letter and any letter following a hyphen to upper case; the rest are converted to lowercase. For example, the canonical key for "accept-encoding" is "Accept-Encoding". If s contains a space or invalid header field bytes, it is returned without modifications.
hasToken reports whether token appears with v, ASCII case-insensitive, with space or comma boundaries. token must be all lowercase. v may contain mixed cased.
func (,  string) bool {
	if len() > len() ||  == "" {
		return false
	}
	if  ==  {
		return true
	}
Check that first character is good. The token is ASCII, so checking only a single byte is sufficient. We skip this potential starting position if both the first byte and its potential ASCII uppercase equivalent (b|0x20) don't match. False positives ('^' => '~') are caught by EqualFold.
		if  := [];  != [0] && |0x20 != [0] {
			continue
Check that start pos is on a valid token boundary.
		if  > 0 && !isTokenBoundary([-1]) {
			continue
Check that end pos is on a valid token boundary.
		if  :=  + len();  != len() && !isTokenBoundary([]) {
			continue
		}
		if strings.EqualFold([:+len()], ) {
			return true
		}
	}
	return false
}

func ( byte) bool {
	return  == ' ' ||  == ',' ||  == '\t'