/** This is called repeatedly by parseSIPMessage to parse * the contents of a message buffer. This assumes the message * already has continuations etc. taken care of. * prior to its being called. */ func (this *StringMsgParser) ParseMessage(currentMessage string) (message.Message, error) { var err error sip_message_size := 0 // # of lines in the sip message var sipmsg message.Message tokenizer := core.NewStringTokenizer(currentMessage) this.messageHeaders = make(map[int]string) // A list of headers for error reporting for tokenizer.HasMoreChars() { nexttok := tokenizer.NextToken() if nexttok == "\n" { nextnexttok := tokenizer.NextToken() if nextnexttok == "\n" { break } else { this.messageHeaders[sip_message_size] = nextnexttok } } else { this.messageHeaders[sip_message_size] = nexttok } sip_message_size++ } this.currentLine = 0 this.currentHeader = this.messageHeaders[this.currentLine] firstLine := this.currentHeader if !strings.HasPrefix(firstLine, header.SIPConstants_SIP_VERSION_STRING) { sipmsg = message.NewSIPRequest() var rl *header.RequestLine if rl, err = NewRequestLineParser(firstLine + "\n").Parse(); err != nil { if this.parseExceptionListener != nil { if err = this.parseExceptionListener.HandleException(err, sipmsg, firstLine, currentMessage); err != nil { return nil, err } } else { return nil, err } } sipmsg.(*message.SIPRequest).SetRequestLine(rl) } else { sipmsg = message.NewSIPResponse() var sl *header.StatusLine if sl, err = NewStatusLineParser(firstLine + "\n").Parse(); err != nil { if this.parseExceptionListener != nil { if err = this.parseExceptionListener.HandleException(err, sipmsg, firstLine, currentMessage); err != nil { return nil, err } } else { return nil, err } } sipmsg.(*message.SIPResponse).SetStatusLine(sl) } for i := 1; i < len(this.messageHeaders); i++ { hdrstring := this.messageHeaders[i] if hdrstring == "" || strings.TrimSpace(hdrstring) == "" { continue } var hdrParser Parser if hdrParser, err = CreateParser(hdrstring + "\n"); err != nil { if this.parseExceptionListener != nil { if err = this.parseExceptionListener.HandleException(err, sipmsg, hdrstring, currentMessage); err != nil { return nil, err } } else { return nil, err } } var sipHeader header.Header if sipHeader, err = hdrParser.Parse(); err != nil { if this.parseExceptionListener != nil { if err = this.parseExceptionListener.HandleException(err, sipmsg, hdrstring, currentMessage); err != nil { return nil, err } } else { return nil, err } } if _, ok := sipmsg.(*message.SIPRequest); ok { if cseq, present := sipHeader.(*header.CSeq); present { if cseq.GetMethod() != sipmsg.(*message.SIPRequest).GetMethod() { return nil, errors.New("Start Line and CSeq Method Mismatch") } } sipmsg.(*message.SIPRequest).AttachHeader2(sipHeader, false) } else { sipmsg.(*message.SIPResponse).AttachHeader2(sipHeader, false) } } return sipmsg, nil }
/** Parse a buffer containing a single SIP Message where the body * is an array of un-interpreted bytes. This is intended for parsing * the message from a memory buffer when the buffer. * Incorporates a bug fix for a bug that was noted by Will Sullin of * Callcast * @param msgBuffer a byte buffer containing the messages to be parsed. * This can consist of multiple SIP Messages concatenated toGether. * @return a SIPMessage[] structure (request or response) * containing the parsed SIP message. * @exception SIPIllegalMessageException is thrown when an * illegal message has been encountered (and * the rest of the buffer is discarded). * @see ParseExceptionListener */ func (this *StringMsgParser) ParseSIPMessageFromByte(msgBuffer []byte) (message.Message, error) { this.bufferPointer = 0 this.bodyIsString = false this.currentMessageBytes = msgBuffer var s int // Squeeze out leading CRLF // Squeeze out the leading nulls (otherwise the parser will crash) // Bug noted by Will Sullin of Callcast for s = this.bufferPointer; s < len(msgBuffer); s++ { if msgBuffer[s] != '\r' && msgBuffer[s] != '\n' { break } } if s == len(msgBuffer) { return nil, nil } // Find the end of the SIP message. var f int for f = s; f < len(msgBuffer)-4; f++ { if msgBuffer[f] == '\r' && msgBuffer[f+1] == '\n' && msgBuffer[f+2] == '\r' && msgBuffer[f+3] == '\n' { break } } if f < len(msgBuffer) { f += 4 } else { // Could not find CRLFCRLF end of message so look for LFLF for f = s; f < len(msgBuffer)-2; f++ { if msgBuffer[f] == '\n' && msgBuffer[f] == '\n' { break } } if f < len(msgBuffer) { f += 2 } else { return nil, errors.New("ParseException: Message not terminated") } } // Encode the body as a UTF-8 string. var messageString string messageString = string(msgBuffer[s:f]) //, "UTF-8"); this.bufferPointer = f message := []byte(messageString) length := len(message) // Get rid of CR to make it uniform for the parser. for k := 0; k < length; k++ { if message[k] == '\r' { copy(message[k:length-1], message[k+1:length]) length-- } } // The following can be written more efficiently in a single pass // but it is somewhat tricky. tokenizer := core.NewStringTokenizer(string(message[:length])) var cooked_message bytes.Buffer for tokenizer.HasMoreChars() { nexttok := tokenizer.NextToken() // Ignore blank lines with leading spaces or tabs. if strings.TrimSpace(nexttok) == "" { cooked_message.WriteString("\n") } else { cooked_message.WriteString(nexttok) } } message1 := cooked_message.String() length = strings.Index(message1, "\n\n") + 2 // Handle continuations - look for a space or a tab at the start // of the line and append it to the previous line. var cooked_message1 bytes.Buffer for k := 0; k < length-1; { if message1[k] == '\n' { if message1[k+1] == '\t' || message1[k+1] == ' ' { k++ k++ if k == length { break } else { continue } } else { cooked_message1.WriteByte(message1[k]) } if message1[k+1] == '\n' { cooked_message1.WriteByte('\n') } } else { cooked_message1.WriteByte(message1[k]) } k++ } cooked_message1.WriteString("\n\n") cooked_message1.WriteString(message1[length:]) // Separate the string out into substrings for // error reporting. this.currentMessage = cooked_message1.String() sipmsg, err := this.ParseMessage(this.currentMessage) if err != nil { return nil, err } if this.readBody && sipmsg.GetContentLength() != nil && sipmsg.GetContentLength().GetContentLength() != 0 { this.contentLength = sipmsg.GetContentLength().GetContentLength() endIndex := this.bufferPointer + this.contentLength // guard against bad specifications. if endIndex > len(this.currentMessageBytes) { return nil, errors.New("Content Length Larger Than Message") } body := this.GetBodyAsBytes() sipmsg.SetMessageContentFromByte(body) } return sipmsg, nil }