mirror of
				https://github.com/aler9/gortsplib
				synced 2025-10-31 10:36:26 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			149 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package base
 | |
| 
 | |
| import (
 | |
| 	"bufio"
 | |
| 	"fmt"
 | |
| 	"net/http"
 | |
| 	"sort"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	headerMaxEntryCount  = 255
 | |
| 	headerMaxKeyLength   = 512
 | |
| 	headerMaxValueLength = 2048
 | |
| )
 | |
| 
 | |
| func headerKeyNormalize(in string) string {
 | |
| 	switch strings.ToLower(in) {
 | |
| 	case "rtp-info":
 | |
| 		return "RTP-Info"
 | |
| 
 | |
| 	case "www-authenticate":
 | |
| 		return "WWW-Authenticate"
 | |
| 
 | |
| 	case "cseq":
 | |
| 		return "CSeq"
 | |
| 	}
 | |
| 	return http.CanonicalHeaderKey(in)
 | |
| }
 | |
| 
 | |
| // HeaderValue is an header value.
 | |
| type HeaderValue []string
 | |
| 
 | |
| // Header is a RTSP reader, present in both Requests and Responses.
 | |
| type Header map[string]HeaderValue
 | |
| 
 | |
| func (h *Header) unmarshal(br *bufio.Reader) error {
 | |
| 	*h = make(Header)
 | |
| 	count := 0
 | |
| 
 | |
| 	for {
 | |
| 		byt, err := br.ReadByte()
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		if byt == '\r' {
 | |
| 			err := readByteEqual(br, '\n')
 | |
| 			if err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			break
 | |
| 		}
 | |
| 
 | |
| 		if count >= headerMaxEntryCount {
 | |
| 			return fmt.Errorf("headers count exceeds %d", headerMaxEntryCount)
 | |
| 		}
 | |
| 
 | |
| 		key := string([]byte{byt})
 | |
| 		byts, err := readBytesLimited(br, ':', headerMaxKeyLength-1)
 | |
| 		if err != nil {
 | |
| 			return fmt.Errorf("value is missing")
 | |
| 		}
 | |
| 
 | |
| 		key += string(byts[:len(byts)-1])
 | |
| 		key = headerKeyNormalize(key)
 | |
| 
 | |
| 		// https://tools.ietf.org/html/rfc2616
 | |
| 		// The field value MAY be preceded by any amount of spaces
 | |
| 		for {
 | |
| 			byt, err := br.ReadByte()
 | |
| 			if err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 
 | |
| 			if byt != ' ' {
 | |
| 				break
 | |
| 			}
 | |
| 		}
 | |
| 		br.UnreadByte()
 | |
| 
 | |
| 		byts, err = readBytesLimited(br, '\r', headerMaxValueLength)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		val := string(byts[:len(byts)-1])
 | |
| 
 | |
| 		err = readByteEqual(br, '\n')
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		(*h)[key] = append((*h)[key], val)
 | |
| 		count++
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (h Header) marshalSize() int {
 | |
| 	// sort headers by key
 | |
| 	// in order to obtain deterministic results
 | |
| 	keys := make([]string, len(h))
 | |
| 	for key := range h {
 | |
| 		keys = append(keys, key)
 | |
| 	}
 | |
| 	sort.Strings(keys)
 | |
| 
 | |
| 	n := 0
 | |
| 
 | |
| 	for _, key := range keys {
 | |
| 		for _, val := range h[key] {
 | |
| 			n += len([]byte(key + ": " + val + "\r\n"))
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	n += 2
 | |
| 
 | |
| 	return n
 | |
| }
 | |
| 
 | |
| func (h Header) marshalTo(buf []byte) int {
 | |
| 	// sort headers by key
 | |
| 	// in order to obtain deterministic results
 | |
| 	keys := make([]string, len(h))
 | |
| 	for key := range h {
 | |
| 		keys = append(keys, key)
 | |
| 	}
 | |
| 	sort.Strings(keys)
 | |
| 
 | |
| 	pos := 0
 | |
| 
 | |
| 	for _, key := range keys {
 | |
| 		for _, val := range h[key] {
 | |
| 			pos += copy(buf[pos:], []byte(key+": "+val+"\r\n"))
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	pos += copy(buf[pos:], []byte("\r\n"))
 | |
| 
 | |
| 	return pos
 | |
| }
 | |
| 
 | |
| func (h Header) marshal() []byte {
 | |
| 	buf := make([]byte, h.marshalSize())
 | |
| 	h.marshalTo(buf)
 | |
| 	return buf
 | |
| }
 | 
