// 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. Get assumes that all
// keys are stored in canonical form. 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  {
		if  == nil {
			// Preserve nil values. ReverseProxy distinguishes
			// between nil and zero-length header values.
			[] = nil
			continue
		}
		 := 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
}

// headerSorter contains a slice of keyValues sorted by keyValues.key.
type headerSorter struct {
	kvs []keyValues
}

var headerSorterPool = sync.Pool{
	New: func() any { 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 = 
	slices.SortFunc(.kvs, func(,  keyValues) int { return strings.Compare(.key, .key) })
	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  {
		if !httpguts.ValidHeaderFieldName(.key) {
			// This could be an error. In the common case of
			// writing response headers, however, we have no good
			// way to provide the error back to the server
			// handler, so just drop invalid headers instead.
			continue
		}
		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.
func ( string) string { return textproto.CanonicalMIMEHeaderKey() }

// 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 hasToken(,  string) bool {
	if len() > len() ||  == "" {
		return false
	}
	if  ==  {
		return true
	}
	for  := 0;  <= len()-len(); ++ {
		// 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 ascii.EqualFold([:+len()], ) {
			return true
		}
	}
	return false
}

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