コード例 #1
0
ファイル: StringMsgParser.go プロジェクト: hinike/gosips
/** 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
}
コード例 #2
0
ファイル: StringMsgParser.go プロジェクト: hinike/gosips
/** 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
}