parseMessage function

IncomingMessage? parseMessage(
  1. String data,
  2. PitelUA? ua
)

Parse SIP Message

Implementation

IncomingMessage? parseMessage(String data, PitelUA? ua) {
  IncomingMessage message;
  int bodyStart;
  int headerEnd = data.indexOf('\r\n');

  if (headerEnd == -1) {
    logger.error('parseMessage() | no CRLF found, not a SIP message');
    return null;
  }

  // Parse first line. Check if it is a Request or a Reply.
  String firstLine = data.substring(0, headerEnd);
  dynamic parsed;
  try {
    parsed = Grammar.parse(firstLine, 'Request_Response');
  } catch (FormatException) {
    // Catch exception and fake the expected -1 result
    parsed = -1;
  }

  if (parsed == -1) {
    logger.error(
        'parseMessage() | error parsing first line of SIP message: "$firstLine"');

    return null;
  } else if (parsed.status_code == null) {
    IncomingRequest incomingRequest = IncomingRequest(ua);
    incomingRequest.method = parsed.method;
    incomingRequest.ruri = parsed.uri;
    message = incomingRequest;
  } else {
    message = IncomingResponse();
    message.status_code = parsed.status_code;
    message.reason_phrase = parsed.reason_phrase;
  }

  message.data = data;
  int headerStart = headerEnd + 2;

  /* Loop over every line in data. Detect the end of each header and parse
  * it or simply add to the headers collection.
  */
  while (true) {
    headerEnd = getHeader(data, headerStart);

    // The SIP message has normally finished.
    if (headerEnd == -2) {
      bodyStart = headerStart + 2;
      break;
    }
    // Data.indexOf returned -1 due to a malformed message.
    else if (headerEnd == -1) {
      logger.error('parseMessage() | malformed message');

      return null;
    }

    parsed = parseHeader(message, data, headerStart, headerEnd);

    if (parsed != true) {
      logger.error('parseMessage() |' + parsed['error']);
      return null;
    }

    headerStart = headerEnd + 2;
  }

  /* RFC3261 18.3.
   * If there are additional bytes in the transport packet
   * beyond the end of the body, they MUST be discarded.
   */
  if (message.hasHeader('content-length')) {
    dynamic headerContentLength = message.getHeader('content-length');

    if (headerContentLength is String) {
      headerContentLength = int.tryParse(headerContentLength) ?? 0;
    }
    headerContentLength ??= 0;

    if (headerContentLength > 0) {
      List<int> actualContent = utf8.encode(data.substring(bodyStart));
      if (headerContentLength != actualContent.length) {
        logger.w(
            '${message.method} received with content-length: $headerContentLength but actual length is: ${actualContent.length}');
      }
      List<int> encodedBody = utf8.encode(data.substring(bodyStart));
      List<int> content = encodedBody.sublist(0, actualContent.length);
      message.body = utf8.decode(content);
    }
  } else {
    message.body = data.substring(bodyStart);
  }

  return message;
}