func ParseStatusLine(statusLine string) (
	sipVersion string, statusCode sip.StatusCode, reasonPhrase string, err error) {
	parts := strings.Split(statusLine, " ")
	if len(parts) < 3 {
		err = fmt.Errorf("status line has too few spaces: '%s'", statusLine)
		return
	}
	sipVersion = parts[0]
	statusCodeRaw, err := strconv.ParseUint(parts[1], 10, 16)
	statusCode = sip.StatusCode(statusCodeRaw)
	reasonPhrase = strings.Join(parts[2:], " ")
	return
}
Parse the first line of a SIP response, e.g:
SIP/2.0 200 OK
SIP/1.0 403 Forbidden
package parser
import (
	"bytes"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"sync"
	"unicode"
	"unicode/utf8"
	"github.com/ghettovoice/gosip/log"
	"github.com/ghettovoice/gosip/sip"
	"github.com/ghettovoice/gosip/util"
)
const abnfWs = " \t"
const maxCseq = 2147483647
type Parser interface {
	Write(p []byte) (n int, err error)
	SetHeaderParser(headerName string, headerParser HeaderParser)
	Stop()
	String() string
	Reset()
	ParseHeader(headerText string) (headers []sip.Header, err error)
}
type HeaderParser func(headerName string, headerData string) ([]sip.Header, error)
func defaultHeaderParsers() map[string]HeaderParser {
	return map[string]HeaderParser{
		"to":             parseAddressHeader,
		"t":              parseAddressHeader,
		"from":           parseAddressHeader,
		"f":              parseAddressHeader,
		"contact":        parseAddressHeader,
		"m":              parseAddressHeader,
		"call-id":        parseCallId,
		"i":              parseCallId,
		"cseq":           parseCSeq,
		"via":            parseViaHeader,
		"v":              parseViaHeader,
		"max-forwards":   parseMaxForwards,
		"content-length": parseContentLength,
		"l":              parseContentLength,
		"expires":        parseExpires,
		"user-agent":     parseUserAgent,
		"allow":          parseAllow,
		"content-type":   parseContentType,
		"c":              parseContentType,
		"accept":         parseAccept,
		"require":        parseRequire,
		"supported":      parseSupported,
		"k":              parseSupported,
		"route":          parseRouteHeader,
		"record-route":   parseRecordRouteHeader,
	}
}
func ParseMessage(msgData []byte, logger log.Logger) (sip.Message, error) {
	output := make(chan sip.Message, 0)
	errs := make(chan error, 0)
	parser := NewParser(output, errs, false, logger)
	defer parser.Stop()
	if _, err := parser.Write(msgData); err != nil {
		return nil, err
	}
	select {
	case msg := <-output:
		return msg, nil
	case err := <-errs:
		return nil, err
	}
}
func NewParser(
	output chan<- sip.Message,
	errs chan<- error,
	streamed bool,
	logger log.Logger,
) Parser {
	p := &parser{
		streamed: streamed,
		done:     make(chan struct{}),
	}
	p.log = logger.
		WithPrefix("parser.Parser").
		WithFields(log.Fields{
			"parser_ptr": fmt.Sprintf("%p", p),
		})
	p.headerParsers = make(map[string]HeaderParser)
	for headerName, headerParser := range defaultHeaderParsers() {
		p.SetHeaderParser(headerName, headerParser)
	}
	p.output = output
	p.errs = errs
	p.bodyLengths.Init()
	p.bodyLengths.SetLog(p.Log())
	if !streamed {
		p.bodyLengths.Run()
	}
	p.input = newParserBuffer(p.Log())
	go p.parse(streamed)
	return p
}
type parser struct {
	headerParsers map[string]HeaderParser
	streamed      bool
	input         *parserBuffer
	bodyLengths   util.ElasticChan
	mu            sync.Mutex
	output chan<- sip.Message
	errs   chan<- error
	terminalErr error
	stopped     bool
	done        chan struct{}
	log log.Logger
}
func (p *parser) String() string {
	if p == nil {
		return "Parser <nil>"
	}
	return fmt.Sprintf("Parser %p", p)
}
func (p *parser) Log() log.Logger {
	return p.log
}
func (p *parser) setError(err error) {
	p.mu.Lock()
	defer p.mu.Unlock()
	p.terminalErr = err
}
func (p *parser) getError() error {
	p.mu.Lock()
	defer p.mu.Unlock()
	return p.terminalErr
}
func (p *parser) Write(data []byte) (int, error) {
	if p.stopped {
		return 0, WriteError(fmt.Sprintf("cannot write data to stopped %s", p))
	}
	if !p.streamed {
		bl := getBodyLength(data)
		if bl == -1 {
			return 0, InvalidMessageFormat(fmt.Sprintf("%s cannot write data: double CRLF sequence not found in the input data", p))
		}
		p.bodyLengths.In <- []int{bl, len(data)}
	}
	num, err := p.input.Write(data)
	if err != nil {
		return 0, WriteError(fmt.Sprintf("%s write data failed: %s", p, err))
	}
	p.Log().Tracef("write %d bytes to input buffer", num)
	return len(data), nil
}
func (p *parser) Stop() {
	p.Log().Debug("stopping parser...")
	p.stopped = true
	p.input.Stop()
	if !p.streamed {
		p.bodyLengths.Stop()
	}
	<-p.done
	p.Log().Debug("parser stopped")
}
func (p *parser) Reset() {
	p.done = make(chan struct{})
	p.stopped = false
	p.setError(nil)
	go p.parse(p.streamed)
}
func (p *parser) parse(requireContentLength bool) {
	defer close(p.done)
	var msg sip.Message
	p.Log().Debug("start parsing")
	defer p.Log().Debug("stop parsing")
	for {
		startLine, err := p.input.NextLine()
		if err != nil {
			break
		}
		p.Log().Tracef("start reading start line: %s", startLine)
		var termErr error
		if isRequest(startLine) {
			method, recipient, sipVersion, err := ParseRequestLine(startLine)
			if err == nil {
				msg = sip.NewRequest("", method, recipient, sipVersion, []sip.Header{}, "", nil)
			} else {
				termErr = err
			}
		} else if isResponse(startLine) {
			sipVersion, statusCode, reason, err := ParseStatusLine(startLine)
			if err == nil {
				msg = sip.NewResponse("", sipVersion, statusCode, reason, []sip.Header{}, "", nil)
			} else {
				termErr = err
			}
		} else {
			termErr = fmt.Errorf("transmission beginning '%s' is not a SIP message", startLine)
		}
		if termErr != nil {
			p.Log().Tracef("%s failed to read start line '%s'", p, startLine)
			termErr = InvalidStartLineError(fmt.Sprintf("%s failed to parse first line of message: %s", p, termErr))
			p.setError(termErr)
			p.errs <- termErr
			if !p.streamed {
				slice := (<-p.bodyLengths.Out).([]int)
				skip := slice[1] - len(startLine) - 2
				p.Log().Tracef("skip %d - %d - 2 = %d bytes", p, slice[1], len(startLine), skip)
				if _, err := p.input.NextChunk(skip); err != nil {
					p.Log().Errorf("skip failed: %s", err)
				}
			}
			continue
		}
		var buffer bytes.Buffer
		headers := make([]sip.Header, 0)
		flushBuffer := func() {
			if buffer.Len() > 0 {
				newHeaders, err := p.ParseHeader(buffer.String())
				if err == nil {
					headers = append(headers, newHeaders...)
				} else {
					p.Log().Warnf("skip header '%s' due to error: %s", buffer, err)
				}
				buffer.Reset()
			}
		}
		for {
			line, err := p.input.NextLine()
			if err != nil {
				break
			}
			if len(line) == 0 {
				flushBuffer()
				break
			}
			if !strings.Contains(abnfWs, string(line[0])) {
				flushBuffer()
				buffer.WriteString(line)
			} else if buffer.Len() > 0 {
				buffer.WriteString(" ")
				buffer.WriteString(line)
			} else {
				p.Log().Tracef(
					"discard unexpected continuation line '%s' at start of header block in message '%s'",
					line,
					msg.Short(),
				)
			}
		}
		for _, header := range headers {
			msg.AppendHeader(header)
		}
		var contentLength int
		if p.streamed {
			contentLengthHeaders := msg.GetHeaders("Content-Length")
			if len(contentLengthHeaders) == 0 {
				termErr := &sip.MalformedMessageError{
					Err: fmt.Errorf("missing required 'Content-Length' header"),
					Msg: msg.String(),
				}
				p.setError(termErr)
				p.errs <- termErr
				continue
			} else if len(contentLengthHeaders) > 1 {
				var errbuf bytes.Buffer
				errbuf.WriteString("multiple 'Content-Length' headers on message '")
				errbuf.WriteString(msg.Short())
				errbuf.WriteString(fmt.Sprintf("'; parser: %s:\n", p))
				for _, header := range contentLengthHeaders {
					errbuf.WriteString("\t")
					errbuf.WriteString(header.String())
				}
				termErr := &sip.MalformedMessageError{
					Err: errors.New(errbuf.String()),
					Msg: msg.String(),
				}
				p.setError(termErr)
				p.errs <- termErr
				continue
			}
			contentLength = int(*(contentLengthHeaders[0].(*sip.ContentLength)))
		} else {
			slice := (<-p.bodyLengths.Out).([]int)
			contentLength = slice[0]
		}
		body, err := p.input.NextChunk(contentLength)
		if err != nil {
			termErr := &sip.BrokenMessageError{
				Err: fmt.Errorf("read message body failed: %w", err),
				Msg: msg.String(),
			}
			p.setError(termErr)
			p.errs <- termErr
			continue
		}
		if len(body) != contentLength {
			termErr := &sip.BrokenMessageError{
				Err: fmt.Errorf(
					"incomplete message body: read %d bytes, expected %d bytes",
					len(body),
					contentLength,
				),
				Msg: msg.String(),
			}
			p.setError(termErr)
			p.errs <- termErr
			continue
		}
		if strings.TrimSpace(body) != "" {
			msg.SetBody(body, false)
		}
		p.output <- msg
	}
	return
}
func (p *parser) SetHeaderParser(headerName string, headerParser HeaderParser) {
	headerName = strings.ToLower(headerName)
	p.headerParsers[headerName] = headerParser
}
func getBodyLength(data []byte) int {
	s := string(data)
	idx := strings.Index(s, "\r\n\r\n")
	if idx == -1 {
		return -1
	}
	bodyStart := idx + 4
	return len(s) - bodyStart
}
func isRequest(startLine string) bool {
	if strings.Count(startLine, " ") != 2 {
		return false
	}
	parts := strings.Split(startLine, " ")
	if len(parts) < 3 {
		return false
	} else if len(parts[2]) < 3 {
		return false
	} else {
		return strings.ToUpper(parts[2][:3]) == "SIP"
	}
}
func isResponse(startLine string) bool {
	if strings.Count(startLine, " ") < 2 {
		return false
	}
	parts := strings.Split(startLine, " ")
	if len(parts) < 3 {
		return false
	} else if len(parts[0]) < 3 {
		return false
	} else {
		return strings.ToUpper(parts[0][:3]) == "SIP"
	}
}
func ParseRequestLine(requestLine string) (
	method sip.RequestMethod, recipient sip.Uri, sipVersion string, err error) {
	parts := strings.Split(requestLine, " ")
	if len(parts) != 3 {
		err = fmt.Errorf("request line should have 2 spaces: '%s'", requestLine)
		return
	}
	method = sip.RequestMethod(strings.ToUpper(parts[0]))
	recipient, err = ParseUri(parts[1])
	sipVersion = parts[2]
	switch recipient.(type) {
	case *sip.WildcardUri:
		err = fmt.Errorf("wildcard URI '*' not permitted in request line: '%s'", requestLine)
	}
	return
}