github.com/cnotch/ipchub@v1.1.0/av/format/rtsp/header.go (about)

     1  // Copyright (c) 2019,CAOHONGJU All rights reserved.
     2  // Use of this source code is governed by a MIT-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package rtsp
     6  
     7  import (
     8  	"bufio"
     9  	"fmt"
    10  	"io"
    11  	"sort"
    12  	"strconv"
    13  	"strings"
    14  	"sync"
    15  )
    16  
    17  // RTSP 头部域定义
    18  // type:support:methods
    19  // type: "g"通用的请求头部;"R"请求头部;"r"响应头部;"e"实体Body头部域。
    20  // support: opt. 可选; req. 必须
    21  // methods: 头部域应用范围
    22  const (
    23  	FieldAccept            = "Accept"             // (R:opt.:entity)
    24  	FieldAcceptEncoding    = "Accept-Encoding"    // (R:opt.:entity)
    25  	FieldAcceptLanguage    = "Accept-Language"    // (R:opt.:all)
    26  	FieldAllow             = "Allow"              // (R:opt.:all)
    27  	FieldAuthorization     = "Authorization"      // (R:opt.:all)
    28  	FieldBandwidth         = "Bandwidth"          // (R:opt.all)
    29  	FieldBlocksize         = "Blocksize"          // (R:opt.:all but OPTIONS, TEARDOWN)
    30  	FieldCacheControl      = "Cache-Control"      // (g:opt.:SETUP)
    31  	FieldConference        = "Conference"         // (R:opt.:SETUP)
    32  	FieldConnection        = "Connection"         // (g:req.:all)
    33  	FieldContentBase       = "Content-Base"       // (e:opt.:entity)
    34  	FieldContentEncoding   = "Content-Encoding"   // (e:req.:SET_PARAMETER ; e:req.:DESCRIBE, ANNOUNCE )
    35  	FieldContentLanguage   = "Content-Language"   // (e:req.:DESCRIBE, ANNOUNCE)
    36  	FieldContentLength     = "Content-Length"     // (e:req.:SET_PARAMETER, ANNOUNCE; e:req.:entity)
    37  	FieldContentLocation   = "Content-Location"   // (e:opt.:entity)
    38  	FieldContentType       = "Content-Type"       // (e:req.:SET_PARAMETER, ANNOUNCE; r:req.:entity )
    39  	FieldCSeq              = "CSeq"               // (g:req.:all)
    40  	FieldDate              = "Date"               // (g:opt.:all)
    41  	FieldExpires           = "Expires"            // (e:opt.:DESCRIBE, ANNOUNCE)
    42  	FieldFrom              = "From"               // (R:opt.:all)
    43  	FieldIfModifiedSince   = "If-Modified-Since"  // (R:opt.:DESCRIBE, SETUP)
    44  	FieldLastModified      = "Last-Modified"      // (e:opt.:entity)
    45  	FieldProxyAuthenticate = "Proxy-Authenticate" //
    46  	FieldProxyRequire      = "Proxy-Require"      // (R:req.:all)
    47  	FieldPublic            = "Public"             // (r:opt.:all)
    48  	FieldRange             = "Range"              // (R:opt.:PLAY, PAUSE, RECORD; r:opt.:PLAY, PAUSE, RECORD)
    49  	FieldReferer           = "Referer"            // (R:opt.:all)
    50  	FieldRequire           = "Require"            // (R:req.:all)
    51  	FieldRetryAfter        = "Retry-After"        // (r:opt.:all)
    52  	FieldRTPInfo           = "RTP-Info"           // (r:req.:PLAY)
    53  	FieldScale             = "Scale"              // (Rr:opt.:PLAY, RECORD)
    54  	FieldSession           = "Session"            // (Rr:req.:all but SETUP, OPTIONS)
    55  	FieldServer            = "Server"             // (r:opt.:all)
    56  	FieldSpeed             = "Speed"              // (Rr:opt.:PLAY)
    57  	FieldTransport         = "Transport"          // (Rr:req.:SETUP)
    58  	FieldUnsupported       = "Unsupported"        // (r:req.:all)
    59  	FieldUserAgent         = "User-Agent"         // (R:opt.:all)
    60  	FieldVia               = "Via"                // (g:opt.:all)
    61  	FieldWWWAuthenticate   = "WWW-Authenticate"   // (r:opt.:all)
    62  )
    63  
    64  type badStringError struct {
    65  	what string
    66  	str  string
    67  }
    68  
    69  func (e *badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) }
    70  
    71  // Header 表示 RTSP 头部域键值对.
    72  type Header map[string][]string
    73  
    74  // Add 添加键值对到头部.
    75  // 如果建已经存在,则对键值做append操作.
    76  func (h Header) Add(key, value string) {
    77  	key = canonicalKV(key)
    78  	value = canonicalKV(value)
    79  	h[key] = append(h[key], value)
    80  }
    81  
    82  // Set 设置头部指定键的值,操作后该键只有单值.
    83  // 如果键已经存在,则覆盖其值.
    84  func (h Header) Set(key, value string) {
    85  	key = canonicalKV(key)
    86  	value = canonicalKV(value)
    87  	h[key] = []string{value}
    88  }
    89  
    90  // Get 获取指定键的值,方法对键会做规范化处理(textproto.CanonicalMIMEHeaderKey)
    91  // 如果没有值返回“”,如果存在返回第一个值
    92  // 想访问多值,直接使用map方法.
    93  func (h Header) Get(key string) string {
    94  	key = canonicalKV(key)
    95  	v := h[key]
    96  	if len(v) == 0 {
    97  		return ""
    98  	}
    99  	return v[0]
   100  }
   101  
   102  // set 和 Set方法类似,不对 key 进行规范化处理
   103  func (h Header) set(key, value string) {
   104  	h[key] = []string{value}
   105  }
   106  
   107  // get 和 Get方法类似,不对 key 进行规范化处理.
   108  func (h Header) get(key string) string {
   109  	if v := h[key]; len(v) > 0 {
   110  		return v[0]
   111  	}
   112  	return ""
   113  }
   114  
   115  // Del 删除指定 key 的值.
   116  func (h Header) Del(key string) {
   117  	delete(h, canonicalKV(key))
   118  }
   119  
   120  // SetInt 设置头部域整数值
   121  func (h Header) SetInt(key string, value int) {
   122  	h[key] = []string{strconv.Itoa(value)}
   123  }
   124  
   125  // Int 获取头部整数域值
   126  func (h Header) Int(key string) int {
   127  	fv := h.get(key)
   128  	if len(fv) < 1 {
   129  		return 0
   130  	}
   131  
   132  	n, err := strconv.ParseInt(fv, 10, 32)
   133  	if err != nil || n < 0 {
   134  		return 0
   135  	}
   136  
   137  	return int(n)
   138  }
   139  
   140  // Setf 格式化的设置头部域
   141  func (h Header) Setf(key, format string, a ...interface{}) string {
   142  	value := fmt.Sprintf(format, a...)
   143  	h.set(key, value)
   144  	return value
   145  }
   146  
   147  // clone 克隆头部
   148  func (h Header) clone() Header {
   149  	h2 := make(Header, len(h))
   150  	for k, vv := range h {
   151  		vv2 := make([]string, len(vv))
   152  		copy(vv2, vv)
   153  		h2[k] = vv2
   154  	}
   155  	return h2
   156  }
   157  
   158  // ReadHeader 根据规范的格式从 r 中读取 Header
   159  func ReadHeader(r *bufio.Reader) (Header, error) {
   160  	h := make(Header, 6) // 多数情况够了
   161  	for {
   162  		var kv string
   163  		kv, err := readLine(r)
   164  		// 返回错误
   165  		if err != nil {
   166  			return nil, err
   167  		}
   168  
   169  		// 空行,Header读取完成退出循环;
   170  		// 根据 Content-Length 的值来决定是否需要读取Body
   171  		if len(kv) == 0 {
   172  			break
   173  		}
   174  
   175  		i := strings.Index(kv, ":")
   176  		// 没有找到分割符,格式错误
   177  		if i < 0 {
   178  			return nil, &badStringError{"malformed header line: ", kv}
   179  		}
   180  
   181  		key := canonicalKV(kv[:i])
   182  		// 忽略,跳过
   183  		if key == "" {
   184  			continue
   185  		}
   186  		// 忽略key的大小写
   187  		if canonicalKey, ok := canonicalKeys[strings.ToUpper(key)]; ok {
   188  			key = canonicalKey
   189  		}
   190  
   191  		value := canonicalKV(kv[i+1:])
   192  		h[key] = append(h[key], value)
   193  
   194  		// // 可能存在多个值
   195  		// values := strings.Split(kv[i+1:], ",")
   196  		// for _, value := range values {
   197  		// 	value = strings.TrimSpace(value)
   198  		// 	if value == "" { // 忽略空 Value
   199  		// 		continue
   200  		// 	}
   201  		// 	h[key] = append(h[key], value)
   202  		// }
   203  	}
   204  	return h, nil
   205  }
   206  
   207  // Write 根据规范将 Header 输出到 w
   208  func (h Header) Write(w io.Writer) error {
   209  	ws, ok := w.(writeStringer)
   210  	if !ok {
   211  		ws = stringWriter{w}
   212  	}
   213  
   214  	kvs, sorter := h.sortedKeyValues()
   215  	defer headerSorterPool.Put(sorter)
   216  
   217  	for _, kv := range kvs {
   218  		value := strings.Join(kv.values, ", ")
   219  
   220  		for _, s := range []string{kv.key, ": ", value, "\r\n"} {
   221  			if _, err := ws.WriteString(s); err != nil {
   222  				return err
   223  			}
   224  		}
   225  	}
   226  
   227  	// 写 Header 结束行
   228  	ws.WriteString("\r\n")
   229  	return nil
   230  }
   231  
   232  type keyValues struct {
   233  	key    string
   234  	values []string
   235  }
   236  
   237  // A headerSorter implements sort.Interface by sorting a []keyValues
   238  // by key. It's used as a pointer, so it can fit in a sort.Interface
   239  // interface value without allocation.
   240  type headerSorter struct {
   241  	kvs []keyValues
   242  }
   243  
   244  func (s *headerSorter) Len() int           { return len(s.kvs) }
   245  func (s *headerSorter) Swap(i, j int)      { s.kvs[i], s.kvs[j] = s.kvs[j], s.kvs[i] }
   246  func (s *headerSorter) Less(i, j int) bool { return s.kvs[i].key < s.kvs[j].key }
   247  
   248  var headerSorterPool = sync.Pool{
   249  	New: func() interface{} { return new(headerSorter) },
   250  }
   251  
   252  // sortedKeyValues returns h's keys sorted in the returned kvs
   253  // slice. The headerSorter used to sort is also returned, for possible
   254  // return to headerSorterCache.
   255  func (h Header) sortedKeyValues() (kvs []keyValues, hs *headerSorter) {
   256  	hs = headerSorterPool.Get().(*headerSorter)
   257  	if cap(hs.kvs) < len(h) {
   258  		hs.kvs = make([]keyValues, 0, len(h))
   259  	}
   260  	kvs = hs.kvs[:0]
   261  	for k, vv := range h {
   262  		kvs = append(kvs, keyValues{k, vv})
   263  	}
   264  	hs.kvs = kvs
   265  	sort.Sort(hs)
   266  	return kvs, hs
   267  }
   268  
   269  // readLine 读取一行
   270  func readLine(r *bufio.Reader) (string, error) {
   271  	const maxLineLenght = 16 * 1024
   272  
   273  	var line []byte
   274  	for {
   275  		l, more, err := r.ReadLine()
   276  		if err != nil {
   277  			return "", err
   278  		}
   279  		// Avoid the copy if the first call produced a full line.
   280  		if line == nil && !more {
   281  			return string(l), nil
   282  		}
   283  		line = append(line, l...)
   284  		if !more {
   285  			break
   286  		}
   287  		// if len(line) >maxLineLenght {
   288  		// 	return string(line),errors.New("line over the maximum length")
   289  		// }
   290  	}
   291  	return string(line), nil
   292  }
   293  
   294  var headerNewlineToSpace = strings.NewReplacer("\n", " ", "\r", " ")
   295  
   296  func canonicalKV(s string) string {
   297  	return strings.TrimSpace(headerNewlineToSpace.Replace(s))
   298  }
   299  
   300  var canonicalKeys = map[string]string{
   301  	strings.ToUpper(FieldAccept):            FieldAccept,
   302  	strings.ToUpper(FieldAcceptEncoding):    FieldAcceptEncoding,
   303  	strings.ToUpper(FieldAcceptLanguage):    FieldAcceptLanguage,
   304  	strings.ToUpper(FieldAllow):             FieldAllow,
   305  	strings.ToUpper(FieldAuthorization):     FieldAuthorization,
   306  	strings.ToUpper(FieldBandwidth):         FieldBandwidth,
   307  	strings.ToUpper(FieldBlocksize):         FieldBlocksize,
   308  	strings.ToUpper(FieldCacheControl):      FieldCacheControl,
   309  	strings.ToUpper(FieldConference):        FieldConference,
   310  	strings.ToUpper(FieldConnection):        FieldConnection,
   311  	strings.ToUpper(FieldContentBase):       FieldContentBase,
   312  	strings.ToUpper(FieldContentEncoding):   FieldContentEncoding,
   313  	strings.ToUpper(FieldContentLanguage):   FieldContentLanguage,
   314  	strings.ToUpper(FieldContentLength):     FieldContentLength,
   315  	strings.ToUpper(FieldContentLocation):   FieldContentLocation,
   316  	strings.ToUpper(FieldContentType):       FieldContentType,
   317  	strings.ToUpper(FieldCSeq):              FieldCSeq,
   318  	strings.ToUpper(FieldDate):              FieldDate,
   319  	strings.ToUpper(FieldExpires):           FieldExpires,
   320  	strings.ToUpper(FieldFrom):              FieldFrom,
   321  	strings.ToUpper(FieldIfModifiedSince):   FieldIfModifiedSince,
   322  	strings.ToUpper(FieldLastModified):      FieldLastModified,
   323  	strings.ToUpper(FieldProxyAuthenticate): FieldProxyAuthenticate,
   324  	strings.ToUpper(FieldProxyRequire):      FieldProxyRequire,
   325  	strings.ToUpper(FieldPublic):            FieldPublic,
   326  	strings.ToUpper(FieldRange):             FieldRange,
   327  	strings.ToUpper(FieldReferer):           FieldReferer,
   328  	strings.ToUpper(FieldRequire):           FieldRequire,
   329  	strings.ToUpper(FieldRetryAfter):        FieldRetryAfter,
   330  	strings.ToUpper(FieldRTPInfo):           FieldRTPInfo,
   331  	strings.ToUpper(FieldScale):             FieldScale,
   332  	strings.ToUpper(FieldSession):           FieldSession,
   333  	strings.ToUpper(FieldServer):            FieldServer,
   334  	strings.ToUpper(FieldSpeed):             FieldSpeed,
   335  	strings.ToUpper(FieldTransport):         FieldTransport,
   336  	strings.ToUpper(FieldUnsupported):       FieldUnsupported,
   337  	strings.ToUpper(FieldUserAgent):         FieldUserAgent,
   338  	strings.ToUpper(FieldVia):               FieldVia,
   339  	strings.ToUpper(FieldWWWAuthenticate):   FieldWWWAuthenticate,
   340  }