Fixed ticket #940: Multiple header rows with the same name may not be completely processed by PJSIP modules
 - the parser now collect and aggregate all Supported/Require header fields into single header


git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@2985 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h
index 0e46163..b971762 100644
--- a/pjsip/include/pjsip/sip_transport.h
+++ b/pjsip/include/pjsip/sip_transport.h
@@ -385,9 +385,16 @@
 	/** Content-length header. */
 	pjsip_clen_hdr		*clen;
 
-	/** The first Require header. */
+	/** "Require" header containing aggregates of all Require
+	 *  headers found in the message, or NULL. 
+	 */
 	pjsip_require_hdr	*require;
 
+	/** "Supported" header containing aggregates of all Supported
+	 *  headers found in the message, or NULL. 
+	 */
+	pjsip_supported_hdr	*supported;
+
 	/** The list of error generated by the parser when parsing 
 	    this message. 
 	 */
diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c
index a5a8e03..5f004ca 100644
--- a/pjsip/src/pjsip/sip_parser.c
+++ b/pjsip/src/pjsip/sip_parser.c
@@ -1007,11 +1007,17 @@
 	    if (handler) {
 		hdr = (*handler)(ctx);
 
+		/* Note:
+		 *  hdr MAY BE NULL, if parsing does not yield a new header
+		 *  instance, e.g. the values have been added to existing
+		 *  header. See http://trac.pjsip.org/repos/ticket/940
+		 */
+
 		/* Check if we've just parsed a Content-Type header. 
 		 * We will check for a message body if we've got Content-Type 
 		 * header.
 		 */
-		if (hdr->type == PJSIP_H_CONTENT_TYPE) {
+		if (hdr && hdr->type == PJSIP_H_CONTENT_TYPE) {
 		    ctype_hdr = (pjsip_ctype_hdr*)hdr;
 		}
 
@@ -1027,7 +1033,8 @@
 	     * different Contact headers.
 	     * So here we must insert list instead of just insert one header.
 	     */
-	    pj_list_insert_nodes_before(&msg->hdr, hdr);
+	    if (hdr)
+		pj_list_insert_nodes_before(&msg->hdr, hdr);
 	    
 	    /* Parse until EOF or an empty line is found. */
 	} while (!pj_scan_is_eof(scanner) && !IS_NEWLINE(*scanner->curptr));
@@ -1639,7 +1646,14 @@
 	goto end;
     }
 
-    pj_scan_get( scanner, &pconst.pjsip_NOT_COMMA_OR_NEWLINE, &hdr->values[0]);
+    if (hdr->count >= PJ_ARRAY_SIZE(hdr->values)) {
+	/* Too many elements */
+	on_syntax_error(scanner);
+	return;
+    }
+
+    pj_scan_get( scanner, &pconst.pjsip_NOT_COMMA_OR_NEWLINE, 
+		 &hdr->values[hdr->count]);
     hdr->count++;
 
     while (*scanner->curptr == ',') {
@@ -1917,13 +1931,19 @@
 /* Parse Require: header. */
 static pjsip_hdr* parse_hdr_require( pjsip_parse_ctx *ctx )
 {
-    pjsip_require_hdr *hdr = pjsip_require_hdr_create(ctx->pool);
+    pjsip_require_hdr *hdr;
+    pj_bool_t new_hdr = (ctx->rdata->msg_info.require == NULL);
+    
+    if (ctx->rdata && ctx->rdata->msg_info.require) {
+	hdr = ctx->rdata->msg_info.require;
+    } else {
+	hdr = pjsip_require_hdr_create(ctx->pool);
+	ctx->rdata->msg_info.require = hdr;
+    }
+
     parse_generic_array_hdr(hdr, ctx->scanner);
 
-    if (ctx->rdata && ctx->rdata->msg_info.require == NULL)
-        ctx->rdata->msg_info.require = hdr;
-
-    return (pjsip_hdr*)hdr;
+    return new_hdr ? (pjsip_hdr*)hdr : NULL;
 }
 
 /* Parse Retry-After: header. */
@@ -1960,11 +1980,19 @@
 /* Parse Supported: header. */
 static pjsip_hdr* parse_hdr_supported(pjsip_parse_ctx *ctx)
 {
-    pjsip_supported_hdr *hdr = pjsip_supported_hdr_create(ctx->pool);
-    parse_generic_array_hdr(hdr, ctx->scanner);
-    return (pjsip_hdr*)hdr;
-}
+    pjsip_supported_hdr *hdr;
+    pj_bool_t new_hdr = (ctx->rdata->msg_info.supported == NULL);
 
+    if (ctx->rdata && ctx->rdata->msg_info.supported) {
+	hdr = ctx->rdata->msg_info.supported;
+    } else {
+	hdr = pjsip_supported_hdr_create(ctx->pool);
+	ctx->rdata->msg_info.supported = hdr;
+    }
+
+    parse_generic_array_hdr(hdr, ctx->scanner);
+    return new_hdr ? (pjsip_hdr*)hdr : NULL;
+}
 
 /* Parse To: header. */
 static pjsip_hdr* parse_hdr_to( pjsip_parse_ctx *ctx )
diff --git a/tests/pjsua/scripts-sipp/uac-inv-multiple-require.xml b/tests/pjsua/scripts-sipp/uac-inv-multiple-require.xml
new file mode 100644
index 0000000..b0790f6
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uac-inv-multiple-require.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>

+<!DOCTYPE scenario SYSTEM "sipp.dtd">

+

+

+<scenario name="Multiple Require header fields">

+  <!-- UAC with bad ACK causes assertion with pjsip 1.4			-->

+  <send retrans="500">

+    <![CDATA[

+

+      INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0

+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]

+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]

+      To: sut <sip:[service]@[remote_ip]:[remote_port]>

+      Call-ID: [call_id]

+      CSeq: 1 INVITE

+      Contact: sip:sipp@[local_ip]:[local_port]

+      Max-Forwards: 70

+      Require: timer

+      Require: toto

+      Subject: Performance Test

+      Content-Type: application/sdp

+      Content-Length: [len]

+

+      v=0

+      o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]

+      s=-

+      c=IN IP[media_ip_type] [media_ip]

+      t=0 0

+      m=audio [media_port] RTP/AVP 0

+      a=rtpmap:0 PCMU/8000

+

+    ]]>

+  </send>

+

+  <recv response="100"

+        optional="true">

+  </recv>

+

+  <recv response="180" optional="true">

+  </recv>

+

+  <recv response="200" rtd="true">

+  </recv>

+

+  <send>

+    <![CDATA[

+

+      ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0

+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]

+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]

+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]

+      Call-ID: [call_id]

+      CSeq: 1 ACK

+      Contact: sip:sipp@[local_ip]:[local_port]

+      Max-Forwards: 70

+      Subject: Performance Test

+      Content-Length: 0

+

+    ]]>

+  </send>

+

+  <pause/>

+

+  <send retrans="500">

+    <![CDATA[

+

+      BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0

+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=z9hG4bK-1

+      From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]

+      To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]

+      Call-ID: [call_id]

+      CSeq: 2 BYE

+      Contact: sip:sipp@[local_ip]:[local_port]

+      Max-Forwards: 70

+      Subject: Performance Test

+      Content-Length: 0

+

+    ]]>

+  </send>

+

+  <recv response="200" crlf="true">

+  </recv>

+

+  <!-- definition of the response time repartition table (unit is ms)   -->

+  <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>

+

+  <!-- definition of the call length repartition table (unit is ms)     -->

+  <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>

+

+</scenario>

+